我是靠谱客的博主 羞涩微笑,这篇文章主要介绍【嵌入式】STM32-DAC实验&高频DAC输出测试1.DAC基础2.启用DAC的一般步骤3.DAC initial4.DAC高频实验4.实验结果,现在分享给大家,希望可以做个参考。

1.DAC基础

大多数STM32芯片会自带DAC输出模块(12 位数字输入,电压输出型的 DAC)

例如常用的STM32F103RCT6 ( RAM48K  FLASH 256K),芯片的DAC有两个输出通道

本次实验使用单 DAC 通道 1,采用 12 位右对齐格式输出。

 STM32F103 参考手册P185:

DAC过程,简要概括为:给DAC_DORx寄存器赋值,然后DAC模块处理,经过t_setting 后,模拟输出引脚变化  。从STM32F103RCT6 的数据手册查到 t_setting 的最大是 4us。所以 DAC 的转换速度最快是: 1/4μs=250KHz 左右。 同时,这个频率也远小于芯片主频72MHz,满足方波占空比调制-DAC输出的要求。

2.启用DAC的一般步骤

开启PORTA时钟。  STM32F103RCT6的DAC通道1在PA4 。所以先开启引脚A系列的时钟,引脚模式设置为模拟输入(因为使能 DAC 通道之后,相应的 GPIO 引脚会自动与 DAC 的模拟输出相连,设置为输入是为了避免额外的干扰-之后可以测试一下设置输出模式是否可行)

Code:

复制代码
1
2
3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能 PORTA时钟 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //引脚配置 模拟输入

step2:使能DAC1的时钟。 查数据手册,找到DAC模块的时钟,调用固件库中的函数开启:

复制代码
1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );  //使能 DAC 通道时钟

step3:初始化工作模式:

本次使用单通道使能,通道1输出缓存关闭,触发响应关闭,波形发生器(三角、方波)关闭。 只需要最基础的DAC输出,调用的函数是dac固件库中的:

void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct)

函数的参数都在结构体DAC_InitType中定义:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct {   uint32_t DAC_Trigger;   //在此值为 DAC_Trigger_None。   uint32_t DAC_WaveGeneration;     //是否使用波形发生  None   uint32_t DAC_LFSRUnmask_TriangleAmplitude;  //屏蔽/幅值选择器,只有在波形发生时生效   uint32_t DAC_OutputBuffer;          // Disable  DAC1 输出缓存关闭 }DAC_InitTypeDef;

/*是否启用触发功能:有些时候需要按键可调输出的电压值。其中一种方法是使用外部中断EXTI9, 另外一种方法就是使用软件触发。如果将DAC_InitTypeDef.DAC_Trigger设置为DAC_Trigger_None, 那么,不需要其他任何的触发源,直接使用DAC_SetChannelxData(),就可以设定输出电压的大小。如果使用了软件触发,那么,每次在使用DAC_SetChannelxData()修改输出电压后,还需要调用DAC_SoftwareTriggerCmd(),目的是使能软件触发*/

step4:通道1输出使能

复制代码
1
DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC1

step5:设置DAC值:

void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data)

也是固件中的函数,源代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** * @brief Set the specified data holding register value for DAC channel1. * @param DAC_Align: Specifies the data alignment for DAC channel1. * This parameter can be one of the following values: * @arg DAC_Align_8b_R: 8bit right data alignment selected * @arg DAC_Align_12b_L: 12bit left data alignment selected * @arg DAC_Align_12b_R: 12bit right data alignment selected * @param Data : Data to be loaded in the selected data holding register. * @retval None */ void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data) { __IO uint32_t tmp = 0; /* Check the parameters */ assert_param(IS_DAC_ALIGN(DAC_Align)); assert_param(IS_DAC_DATA(Data)); tmp = (uint32_t)DAC_BASE; tmp += DHR12R1_OFFSET + DAC_Align; /* Set the DAC channel1 selected data holding register */ *(__IO uint32_t *) tmp = Data; }

首先第一个参数选12位D输入还是8位D(Right or Left)输入

第二个参数就是输出的值 。注意第二个参数值 12位的话是在0~4095(2^12-1) 8位在0~255

此外,也可以在软件内读取通道输出值:DAC_GetDataOutputValue(DAC_Channel_1);

3.DAC initial

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "dac.h" // //本程序源自: //正点原子@ALIENTEK //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 // //DAC通道1输出初始化 void Dac1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; DAC_InitTypeDef DAC_InitType; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能PORTA通道时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能DAC通道时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_4) ;//PA.4 输出高 DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0 DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生 DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置 DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ; //DAC1输出缓存关闭 BOFF1=1 DAC_Init(DAC_Channel_1,&DAC_InitType); //初始化DAC通道1 DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC1 DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12位右对齐数据格式设置DAC值 } //设置通道1输出电压 //vol:0~3300,代表0~3.3V void Dac1_Set_Vol(u16 vol) { float temp=vol; temp/=1000; temp=temp*4096/3.3; DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值 }

initial函数就是把上面的步骤做了一个封装。

void Dac1_Set_Vol(u16 vol)函数支持float电压换算,不然每次调用DAC_SetChannel1Data()时都得换算一下。

4.DAC高频实验

在主函数里测DAC的最高频,然后在LCD上现实。 首先用一个up-down循环,让DAC输出一直变化,然后每次变化Fre++ 。 每秒在定时器中清空一次Fre,然后记录最高的Fre,即为DAC最高频。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "lcd.h" #include "adc.h" #include "dac.h" #include "timer.h" u32 Fre=0; //extern 变量定义为全局变量 u16 adcx; float temp; u8 dvup=1; u32 HighestFre=0; u16 dacval=0; int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2 delay_init(); //延时函数初始化 uart_init(9600); //串口初始化为9600 LED_Init(); //初始化与LED连接的硬件接口 LCD_Init(); //初始化LCD Adc_Init(); //ADC初始化 Dac1_Init(); //DAC通道1初始化 TIM3_Int_Init(9999,7199);//10Khz的计数频率,计数到10000为1000ms POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(60,50,200,16,16,"Mini STM32"); LCD_ShowString(60,70,200,16,16,"DAC TEST"); LCD_ShowString(60,90,200,16,16,"2020/6/30"); LCD_ShowString(60,120,200,16,16,"HF:"); //显示提示信息 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_SetChannel1Data(DAC_Align_12b_R, 0);//设置DAC1通道 12位R对其,输出0 while(1) { if(dvup){ if(dacval<4000) dacval+=20; else dvup=0; } else{ if(dacval>200) dacval-=20; else dvup=1; } DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//DAC输出 Fre++; } }

在定时器中断中设置刷新LCD,main程序内尽可能快地更新DAC次数。

定时器 timer.c 中的IRQHandler:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
extern u32 Fre; extern u16 adcx; extern float temp; extern u8 dvup; extern u32 HighestFre; extern u16 dacval; u32 tempu32; void TIM3_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源 if(Fre>HighestFre) HighestFre=Fre; tempu32=HighestFre; LCD_ShowxNum(100,120,tempu32,8,16,0); //显示highest frequency adcx=DAC_GetDataOutputValue(DAC_Channel_1);//DAC LCD_ShowxNum(124,150,adcx,4,16,0); //显示DAC寄存器值 temp=(float)adcx*(3.3/4096); //得到DAC电压值 adcx=temp; LCD_ShowxNum(124,170,temp,1,16,0); //显示电压值整数部分 temp-=adcx; temp*=1000; LCD_ShowxNum(140,170,temp,3,16,0X80); //显示电压值的小数部分 adcx=Get_Adc_Average(ADC_Channel_1,10); //得到ADC转换值 temp=(float)adcx*(3.3/4096); //得到ADC电压值 adcx=temp; LCD_ShowxNum(124,190,temp,1,16,0); //显示电压值整数部分 temp-=adcx; temp*=1000; LCD_ShowxNum(140,190,temp,3,16,0X80); //显示电压值的小数部分 LED0=!LED0; Fre=0; } }

4.实验结果

CPU基本都在进行DAC操作。和估计的250kHz在一个量级,但是会高一些,可能是定时器不够准确,以及Tsetting会比标示的更短一些。

主程序循环时,主要耗时的是DAC环节:

    while(1)
    {
        if(dvup){
            if(dacval<4000)  dacval+=20;
            else dvup=0;
        }
        else{
            if(dacval>200)  dacval-=20;
            else dvup=1;
        }
        DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//DAC输出
        Fre++;
    }

 尝试修改源码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/** * @brief Set the specified data holding register value for DAC channel1. * @param DAC_Align: Specifies the data alignment for DAC channel1. * This parameter can be one of the following values: * @arg DAC_Align_8b_R: 8bit right data alignment selected * @arg DAC_Align_12b_L: 12bit left data alignment selected * @arg DAC_Align_12b_R: 12bit right data alignment selected * @param Data : Data to be loaded in the selected data holding register. * @retval None */ void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data) { __IO uint32_t tmp = 0; /* Check the parameters */ //assert_param(IS_DAC_ALIGN(DAC_Align)); //assert_param(IS_DAC_DATA(Data)); tmp = (uint32_t)DAC_BASE; tmp += DHR12R1_OFFSET + DAC_Align; /* Set the DAC channel1 selected data holding register */ *(__IO uint32_t *) tmp = Data; }

修改时把两行 assert_param 注释了,略过了参数检查环节。最高频率几乎没有提升。说明CPU运算不是主要耗时项目。

在主程序中把DAC_SetChannel1Data注释了,测得不带DAC环节其他部分的最高频:

1111kHz,说明循环中其他计算环节耗时约0.9us。

加入DAC环节一次运行耗时约 1/630kHz=1.6us。

 所以进行一次DAC耗时大概占0.7us。这个值比参考手册给出的Tsetting小很多,但是需要注意的是DAC_SetChannel1Data 的源码中貌似没有ACK环节,即没有检测DAC是否已经完成。所以进一步DAC高频极限测试可以使用DAC 方波输出+示波器进行测试。

最后

以上就是羞涩微笑最近收集整理的关于【嵌入式】STM32-DAC实验&高频DAC输出测试1.DAC基础2.启用DAC的一般步骤3.DAC initial4.DAC高频实验4.实验结果的全部内容,更多相关【嵌入式】STM32-DAC实验&高频DAC输出测试1.DAC基础2.启用DAC的一般步骤3.DAC内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部