CKS32F4xx系列DAC功能

电子说

1.2w人已加入

描述

DAC模块作为CKS32F4xx系列的一个常用外设,可以将数字信号转换成模拟信号,最高分辨率可达12位,且两个独立DAC输出通道转换互不影响,各个通道均能使用DMA功能,可由软硬件触发。因此,为了实现DAC输出正弦波,拟采用一定的时间向DAC的数据寄存器写入数据,随后进行数模转换输出不同的电压,最后在时间轴上显示出波形。同时为了不占用CPU资源,配置DMA建立传输通道,以便数据快速的从内存搬移到外设。且在DAC初始化时,可以设置成定时器触发,待定时器溢出就会触发DAC工作,所以只要修改定时器的定时时间,就可改变正弦波周期。

DAC简述

dac

①:DAC将VREF+引脚作为参考电压,在实际使用时将VSSA接地,同时把VREF+和VDDA接3.3V,DAC即可获得0~3.3V的输出电压。

②:数模转换器以VREF+作为参考电源,将DAC的数据寄存器“DORx”的数字编码转换成模拟信号并由右侧的“DAC_OUTx”通道输出。在CKS32有2个这样的DAC部件,其中PA4对应通道1,PA5对应通道2。

③:控制逻辑可以控制数据寄存器“DORx”加入一些伪噪声信号或配置产生三角波信号。

④:使用DAC时,数据会被先写入到DHRx寄存器,随后DAC会根据触发配置进行处理,最后将数据传输至DORx。DAC的触发源有三种,分别为:外部中断源触发、定时器触发和软件控制触发。

对于单DAC通道x的三种数据格式

8位数据右对齐:

用户须将数据写入寄存器DAC_DHR8Rx[7:0]位(实际是存入寄存器DHRx[11:4]位)。

12位数据左对齐:

用户须将数据写入寄存器DAC_DHR12Lx[15:4]位(实际是存入寄存器DHRx[11:0]位)。

12位数据右对齐:

用户须将数据写入寄存器DAC_DHR12Rx[11:0]位(实际是存入寄存器DHRx[11:0]位)。

数字输入经过DAC被线性地转换为模拟电压输出,任一DAC通道引脚上的输出电压满足下面的关系:

本案例中选择DAC的通道1,并采用12位的右对齐方式,通过查阅《CKS32F4xx参考手册》DAC和DMA章节可知,DAC1对应DMA1控制器通道7数据流5。

总的来说,DAC的输出是由DORx寄存器直接控制的,而用户写的数据是要写入DHRx寄存器,然后通过DHRx间接操作DORx,最终实现DAC的输出。

DAC输出正弦波配置

本文采用DAC1+TIM2+DMA1的方式,通过TIM2触发DAC1转换,转换完成后通过DMA1输出,主要步骤如下:

①由Matlab计算一个周期的正弦波数组;

②根据一个正弦波周期内点数和所需正弦波频率确定定时器触发间隔;

③初始化DAC1输出管脚和工作模式;

④配置触发DAC1用的定时器2;

⑤配置DMA1自主搬运正弦波数组。

待上述配置完成后,将PA4引脚接到示波器上,即可显示正弦波。以下是DAC的详细配置。

(1)正弦波数组生成

以下代码用于生成正弦波波形表:

 

for(i=0;i<100;i++)
{
    Sine12bit[i]=2048*sin(1.0*i/(100- 1)*2*PI)+2048;
}

 

从上述函数可以看出,正弦波的幅度被控制在0~4096之间,一个周期被平均分成100份,即100个点代表一个周期的波形,数组Sine12bit里面是100个采样点。

 

const uint16_t Sine12bit[100] = {

0x0800,0x0881,0x0901,0x0980,0x09FD,0x0A79,0x0AF2,0x0B68,0x0BDA,0x0C49,0x0CB3,0x0D19,0x0D79,0x0DD4,0x0E29,0x0E78,0x0EC0,0x0F02,0x0F3C,0x0F6F,0x0F9B,0x0FBF,0x0FDB,0x0FEF,0x0FFB,0x0FFF,0x0FFB,0x0FEF,0x0FDB,0x0FBF,0x0F9B,0x0F6F,0x0F3C,0x0F02,0x0EC0,0x0E78,0x0E29,0x0DD4,0x0D79,0x0D19,0x0CB3,0x0C49,0x0BDA,0x0B68,0x0AF2,0x0A79,0x09FD,0x0980,0x0901,0x0881,0x0800,0x077F,0x06FF,0x0680,0x0603,0x0587,0x050E,0x0498,0x0426,0x03B7,0x034D,0x02E7,0x0287,0x022C,0x01D7,0x0188,0x0140,0x00FE,0x00C4,0x0091,0x0065,0x0041,0x0025,0x0011,0x0005,0x0001,0x0005,0x0011,0x0025,0x0041,0x0065,0x0091,0x00C4,0x00FE,0x0140,0x0188,0x01D7,0x022C,0x0287,0x02E7,0x034D,0x03B7,0x0426,0x0498,0x050E,0x0587,0x0603,0x0680,0x06FF,0x077F};

 

(2)GPIO和DAC模式配置

该部分为输出引脚配置和DAC通道1配置,代码如下:

 

void DAC1_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    DAC_InitTypeDef DAC_InitStructure;
    /*  Enable GPIOA clock  */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);/*  Enable DAC clock  */RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);/*  Configure the DAC Pin to Analog mode: DAC_OUT1 -- PA4  */GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed= GPIO_Speed_100MHz;  
    GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;
    GPIO_Init(GPIOA,  GPIO_InitStructure);
    /*  Configure DAC Channel_1  */
    DAC_InitStructure.DAC_Trigger= DAC_Trigger_T2_TRGO;
    DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;DAC_Init(DAC_Channel_1,  DAC_InitStructure);
    DAC_Cmd(DAC_Channel_1, ENABLE);//Enable DAC Channel_1.
    DAC_DMACmd(DAC_Channel_1, ENABLE);//Enable DAC channel_1 DMA request.
}

 

在DAC1_GPIO_Init函数中,实现了相应GPIO引脚(PA4)的初始化和DAC工作模式配置。其中为了避免寄生的干扰和额外的功耗,应将PA4引脚设置成模拟输入模式(AIN),如此方可正常工作。

而对DAC工作模式进行配置时,可查看CKS官方提供的DAC_InitTypeDef结构体,该结构体中主要包含了DAC_CR寄存器的各寄存器配置。如下是DAC_InitTypeDef结构体成员简述:

(a)DAC_Trigger

该成员用于DAC的触发模式配置,由上文DAC通道框图可知,共有三种触发模式,分别是定时器触发(DAC_Trigger_T2/4/5/6/7/8_TRGO)、软件触发(DAC_Trigger_Software)和EXTI_9触发方式(DAC_Trigger_Ext_IT9)。

(b)DAC_WaveGeneration

该成员可配置输出伪噪声和三角波输出(DAC_WaveGeneration_Noise/Triangle),若使用自定义输出,应配置为DAC_WaveGeneration_None。

(c)DAC_OutputBuffer

该成员用于控制是否使能DAC的输出缓冲(DAC_OutputBuffer_Enable/Disable)。若需要直接驱动外部负载,可以使能该成员以减小输出阻抗。

(d)DAC_LFSRUnmask_TriangleAmplitude

该成员通过控制DAC_CR的MAMP2位设置LFSR寄存器位的数据,即当使用伪噪声或三角波输出时要叠加到DHRx的值。若使用伪噪声输出时LFSR=0xAAA,这时该结构体成员可赋值为DAC_LFSRUnmask_Bit0~DAC_LFSRUnmask_Bit11_0;若使用三角波输出时,这时该结构体成员可赋值为DAC_TriangleAmplitude_1~DAC_TriangleAmplitude_4096,可用于设置三角波的最大幅值。

本例中,将DAC通道1配置成定时器TIM2触发,不使用波形发生器和不使用输出缓存,不使用输出缓存是因为CKS32的DAC无需外部运放就可以直接驱动负载,三角波振幅一项虽然本案例没有用到,可以配置成任意,但此项不可缺,最后调用DAC_Cmd、DAC_DMACmd函数使能DAC通道1和DMA的请求。

(3)定时器配置

该部分是配置触发DAC的定时器TIM2,通过设定触发的间隔,从而间接控制正弦波周期,TIM2的工作决定DMA与DAC的工作频率,代码如下:

 

void TIM2_Init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    /*  Enable Timer2 clock.  */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/*  Configure Timer2 --Clock Frequency is 84MHz  */
    TIM_TimeBaseStructure.TIM_Period=83; TIM_TimeBaseStructure.TIM_Prescaler= 0x0;       
    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2,  TIM_TimeBaseStructure);  /*  Configure the trigger source for Timer2.  */TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
    TIM_Cmd(TIM2, ENABLE);//Enable Timer2.
}

 

前文的DAC已选用TIM2当触发源,此处TIM2的定时周期被配置为83,向上计数,不分频。CKS32F4xx系列的主频是168MHz,TIM2的时钟是84MHz,所以TIM2的更新频率是84M/(TIM_Period+1)/(TIM_Prescaler+1),即TIM2每隔1us触发一次DAC事件,不需要设置中断,当定时器向上计数至指定值时,产生Update事件,同时触发DAC把DHRx寄存器的数据转移到DORx,开始进行转换。由于正弦波数组是100个采样点,可得正弦波的输出频率为:

(4)DMA配置

该部分主要完成数据的传输,代码如下:

 

void DMA_InitForDAC(void)
{
    DMA_InitTypeDef  DMA_InitStructure;
    /*  Enable DMA1 clock.  */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);/*  Configure DMA1 Stream5 Channel_7 For DAC1  */
    DMA_InitStructure.DMA_Channel = DMA_Channel_7;  DMA_InitStructure.DMA_PeripheralBaseAdDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Sine12bit ;DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize = 100;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;      DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA1_Stream5,  DMA_InitStructure);DMA_Cmd(DMA1_Stream5, ENABLE); //Enable DMA1 Stream5.
}

 

需要注意的是,DAC->DHR12R1对应数据寄存器的地址,正弦波数组Sine12bit对应数据输入地址,DMA缓存的个数是单个正弦波周期对应的点数,DMA需工作在循环模式,由于正弦波数组Sine12bit定义为16位,那么涉及数据传输的变量都要配置成半字16位。经过上述的配置后,定时器TIM2每隔1us就会触发DMA搬运正弦波数组的一个数据到DAC通道1寄存器进行转换,每搬运100个数据即一个完整周期后,DMA开始循环,最终循环输出正弦波。

(5)主函数配置

本例程主函数主要对前文所述函数依次调用,程序编译下载至开发板,使用示波器测量PA4引脚即可查看输出10kHz的正弦波形,代码如下:

 

int main(void)   
{
    DAC1_GPIO_Init();
    TIM2_Init();
    DMA_InitForDAC();
    while (1);
}

 

来源:中科芯MCU

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分