当前位置:网站首页>STM32-DAC实验&高频DAC输出测试
STM32-DAC实验&高频DAC输出测试
2022-07-02 11:04:00 【早睡早起的CHERY】
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:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能 PORTA时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //引脚配置 模拟输入
step2:使能DAC1的时钟。 查数据手册,找到DAC模块的时钟,调用固件库中的函数开启:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能 DAC 通道时钟step3:初始化工作模式:
本次使用单通道使能,通道1输出缓存关闭,触发响应关闭,波形发生器(三角、方波)关闭。 只需要最基础的DAC输出,调用的函数是dac固件库中的:
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct)
函数的参数都在结构体DAC_InitType中定义:
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输出使能
DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC1step5:设置DAC值:
void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data)
也是固件中的函数,源代码:
/**
* @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
#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最高频。
#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:
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++;
}
尝试修改源码:
/**
* @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 方波输出+示波器进行测试。
边栏推荐
- Certik released the defi security report in 2021, disclosing key data of industry development (PDF download link attached)
- 线性dp求解 最长子序列 —— 小题三则
- Dangbei projection 4K laser projection X3 Pro received unanimous praise: 10000 yuan projector preferred
- < schéma de développement de la machine d'exercice oral > machine d'exercice oral / trésor d'exercice oral / trésor de mathématiques pour enfants / lecteur LCD de calculatrice pour enfants IC - vk1621
- [development environment] Dell computer system reinstallation (download Dell OS recovery tool | use Dell OS recovery tool to make USB flash disk system | install system)
- 千元投影小明Q1 Pro和极米NEW Play谁更好?和哈趣K1比哪款配置更高?
- 无主灯设计:如何让智能照明更加「智能」?
- 万物生长大会在杭召开,当贝入选2022中国未来独角兽TOP100榜单
- Slashgear shares 2021 life changing technology products, which are somewhat unexpected
- SystemServer进程
猜你喜欢

Launcher启动过程

【虹科技术分享】如何测试 DNS 服务器:DNS 性能和响应时间测试

什么是 eRDMA?丨科普漫画图解

Subcontracting configuration of uniapp applet subpackages

没有从远程服务器‘‘映射到本地用户‘(null)/sa‘的远程用户‘sa‘及服务主密码解密错误的解决办法

The conference on the growth of all things was held in Hangzhou, and dangbei was selected into the top 100 list of future unicorns in China in 2022

Default slot, named slot, scope slot

Origin plots thermogravimetric TG and differential thermogravimetric DTG curves

< schematic diagram of oral arithmetic exercise machine program development> oral arithmetic exercise machine / oral arithmetic treasure / children's math treasure / children's calculator LCD LCD driv
【文档树、设置】字体变小
随机推荐
Mysql5.7 installation super easy tutorial
< schéma de développement de la machine d'exercice oral > machine d'exercice oral / trésor d'exercice oral / trésor de mathématiques pour enfants / lecteur LCD de calculatrice pour enfants IC - vk1621
Téléchargement par navigateur
QT how to set fixed size
NLA自然语言分析实现数据分析零门槛
In 2021, the global TCB adapter revenue was about $93 million, and it is expected to reach $315.5 million in 2028
The conference on the growth of all things was held in Hangzhou, and dangbei was selected into the top 100 list of future unicorns in China in 2022
Daily learning 2
In 2021, the global styrene butadiene styrene (SBS) revenue was about $3722.7 million, and it is expected to reach $5679.6 million in 2028
Selenium, element operation and browser operation methods
Data consistency between redis and database
Do you know that there is an upper limit on the size of Oracle data files?
MySQL45讲——学习极客时间MySQL实战45讲笔记—— 05 | 深入浅出索引(下)
MySQL45讲——学习极客时间MySQL实战45讲笔记—— 04 | 深入浅出索引(上)
[development environment] Dell computer system reinstallation (download Dell OS recovery tool | use Dell OS recovery tool to make USB flash disk system | install system)
The evolution process of the correct implementation principle of redis distributed lock and the summary of redison's actual combat
Some interview suggestions for Android programmers "suggestions collection"
提示:SQL Server 阻止了对组件‘Ad Hoc Distributed Queries ‘的STATEMENT ‘OpenRowset/OpenDatasource“”
PyQt5_ Qscrollarea content is saved as a picture
Essential elements of science fiction 3D scenes - City