1)实验平台:正点原子MiniPro H750开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560 3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-336836-1-1.html 4)对正点原子STM32感兴趣的同学可以加群讨论:879133275
第三十四章 DAC实验
本章,我们将介绍STM32H750的DAC(Digital -to- analog converters,数模转换器)功能。我们通过三个实验来学习DAC,分别是DAC输出实验、DAC输出三角波实验和DAC输出正弦波实验。 本章分为如下几个小节: 34.1 DAC简介 34.2 DAC输出实验 34.3 DAC输出三角波实验 34.4 DAC输出正弦波实验
34.1 DAC简介 STM32H750的DAC模块(数字/模拟转换模块)是12位数字输入,电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压Vref+(通ADC共用)以获得更精确的转换结果。 STM32H750的DAC模块主要特点有: ① 2个DAC转换器:每个转换器对应1个输出通道 ② 8位或者12位单调输出 ③ 12位模式下数据左对齐或者右对齐 ④ 同步更新功能 ⑤ 噪声波形生成 ⑥ 三角波形生成 ⑦ 双DAC双通道同时或者分别转换 ⑧ 每个通道都有DMA功能 DAC通道框图如图34.1.1所示:
图34.1.1 DAC通道框图 图中VDDA和VSSA为DAC模块模拟部分的供电,而VREF+则是DAC模块的参考电压。DAC_OUT1/2就是DAC的两个输出通道了(对应PA4或者PA5引脚)。ADC的这些输入/输出引脚信息如下表所示:
表34.1.1 DAC输入/输出引脚 除了上表列出的输入/输出引脚,DAC通道框图还有一些内部输入/输出信号,具体如下表所示:
表34.1.2 DAC内部输入/输出信号 注意:表中的dac_pclk即DAC的时钟源,DA转换和寄存器访问都是靠这个时钟,该时钟来自APB1,通过sys_stm32_clock_init函数配置之后,为120MHz。 从图34.1.1可以看出,DAC输出是受DORx(x=1/2,下同)寄存器直接控制的,但是我们不能直接往DORx寄存器写入数据,而是通过DHRx间接的传给DORx寄存器,从而实现对DAC输出的控制。 前面我们提到,STM32H750的DAC支持8/12位模式,8位模式的时候是固定的右对齐的,而12位模式又可以设置左对齐/右对齐。DAC单通道模式下的数据寄存器对齐方式,总共有3种情况,如下图所示:
图34.1.2 DAC单通道模式下的数据寄存器对齐方式 ①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通道1,采用12位右对齐格式,所以采用第③种情况。另外DAC还具有双通道转换功能。 对于 DAC 双通道(可用时),也有三种可能的方式,如下图所示:
图34.1.3 DAC双通道模式下的数据寄存器对齐方式 ①8位数据右对齐:用户将DAC通道1的数据写入DAC_DHR8RD[7:0]位(实际存入DHR1 [11:4]位),将DAC通道2的数据写入DAC_DHR8RD[15:8]位(实际存入DHR2 [11:4]位)。 ②12位数据左对齐:用户将DAC通道1的数据写入DAC_DHR12LD [15:4]位(实际存入DHR1[11:0]位),将DAC通道2的数据写入DAC_DHR12LD [31:20]位(实际存入DHR2[11:0]位)。 ③12位数据右对齐:用户将DAC通道1的数据写入DAC_DHR12RD [11:0]位(实际存入DHR1[11:0]位),将DAC通道2的数据写入DAC_DHR12RD [27:16]位(实际存入DHR2[11:0]位)。 DAC可以通过软件或者硬件触发转换,通过配置TENx 控制位来决定。 如果没有选中硬件触发(寄存器DAC_CR1的TENx位置0),存入寄存器DAC_DHRx的数据会在1个APB1时钟周期后自动传至寄存器DAC_DORx。如果选中硬件触发(寄存器DAC_CR1的TENx位置1),数据传输在触发发生以后3个APB1时钟周期后完成。 一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间tSETTLING之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。我们可以从《STM32H750VBT6.pdf》数据手册查到tSETTLING的典型值为1.7us,最大是2us,所以DAC的转换速度最快是588K左右。 不使用硬件触发(TEN=0),其转换的时间框图如图34.1.4所示:
图34.1.4 TEN=0时DAC模块转换时间框图 当DAC的参考电压为VREF+的时候,DAC的输出电压是线性的从0~VREF+,12位模式下DAC输出电压与VREF +以及DORx的计算公式如下: DACx输出电压 = VREF *(DORx/4096) 如果使用硬件触发(TEN=1),可通过外部事件(定时计数器、外部中断线)触发DAC转换。由TSELx[3:0]控制位来决定选择16个触发事件中的一个来触发转换。这16个触发事件如下表所示:
表34.1.3 DAC触发选择 原表见《STM32H7xx参考手册_V3(中文版).pdf》第923页表 208。 每个DAC通道都有DMA功能,两个DMA通道分别用于处理两个DAC通道的DMA 请求。如果DMAENx 位置1时,如果发生外部触发(而不是软件触发),就会产生一个DMA 请求,然后DAC_DHRx寄存器的数据被转移到DAC_NORx寄存器。 34.2 DAC输出实验 本实验我们来学习DAC输出实验。 34.2.1 DAC寄存器 下面,我们介绍要实现DAC的通道1输出,需要用到的一些DAC寄存器。 DACx控制寄存器(DACx_CR)(x=1或2) DACx控制寄存器描述如图34.2.1.1所示:
图34.2.1.1 DACx_CR寄存器 DACx_CR寄存器的低16位用于控制通道1,高16位用于控制通道2,下面介绍本实验需要设置的一些位: EN1位用于使能/禁止DAC通道1,本实验用到ADC1通道1,所以该位EN1置1。 TEN1位用于DAC通道1的触发使能,本实验不使用硬件触发,所以该位置0。写入DHR1的值会在1个APB1周期后传送到DOR1,然后输出到PA4口上。 TSEL[3:0]位用于选择DAC通道1的触发方式,本实验使用软件触发,所以该位域置0。具体的设置关系详见表34.1.3 DAC触发选择。 WAVE[1:0]位用于控制DAC通道1的噪声/波形输出功能,默认设置为00,不使能噪声/波形输出。 DMAEN1位用于控制DAC通道1的DMA使能,本实验不使能,设置该位为0即可。 CEN1位用于控制DAC通道1的输出缓冲校准使能,本实验不使用校准功能(默认有一个出厂校准值,我们使用默认的校准值即可),设置该位为0即可。 DACx模式控制寄存器(DACx_ MCR) DACx模式控制寄存器描述如图34.2.1.2所示:
图34.2.1.2 DACx_ MCR寄存器 该寄存器我们只关心MODE1[2:0],这三个位用于设置DAC通道1的工作模式,本实验使用普通模式,且使用输出缓冲,设置MODE1[2:0]=0即可。MODE2[2:0] 设置通道2的工作模式,本实验没用到。 DACx通道1 12位右对齐数据保持寄存器(DACx_ DHR12R1) DACx通道1 12位右对齐数据保持寄存器描述如图34.2.1.3所示:
图34.2.1.3 DACx_ DHR12R1寄存器 该寄存器用来设置DAC输出,通过写入12位数据到该寄存器,就可以在DAC输出通道1(PA4)得到我们所要的结果。 34.2.2 硬件设计
- 例程功能 使用KEY1/KEY_UP两个按键,控制STM32内部DAC的通道1输出电压大小,然后通过ADC1的通道19采集DAC输出的电压,在LCD模块上面显示ADC采集到的电压值以及DAC的设定输出电压值等信息。也可以通过usmart调用dac_set_voltage函数,来直接设置DAC输出电压。LED0闪烁,提示程序运行。
- 硬件资源 1)RGB灯 RED : LED0 - PB4 2)串口1(PA9/PA10连接在板载USB转串口芯片CH340上面) 3)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动) 4)独立按键 :KEY1 - PA15、WK_UP - PA0 5)ADC1 :通道19 - PA5 6)DAC1 :通道1 - PA4
- 原理图 我们来看看原理图上ADC1通道19(PA5)和DAC1通道1(PA4)引出来的引脚,如下图所示:
图34.2.2.1 ADC和DAC在开发板上的连接关系原理图 P3是多功能端口,我们只需要通过跳线帽连接P3的ADC和DAC,就可以使得ADC1通道19(PA5)和DAC1通道1(PA4)连接起来。对应的硬件连接如图34.2.2.2所示:
图34.2.2.2 硬件连接示意图 34.2.3 程序设计 34.2.3.1 DAC的HAL库驱动 DAC在HAL库中的驱动代码在stm32h7xx_hal_dac.c和stm32h7xx_hal_dac_ex.c文件(及其头文件)中。
- HAL_DAC_Init函数 DAC的初始化函数,其声明如下: HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef *hdac); 函数描述: 用于初始化DAC。 函数形参: 形参1是DAC_HandleTypeDef结构体类型指针变量,其定义如下:
typedef struct
{
DAC_TypeDef *Instance; /* DAC寄存器基地址 */
__IO HAL_DAC_StateTypeDef State; /* DAC 工作状态 */
HAL_LockTypeDef Lock; /* DAC锁定对象 */
DMA_HandleTypeDef *DMA_Handle1; /* 通道1的DMA处理句柄指针 */
DMA_HandleTypeDef *DMA_Handle2; /* 通道2的DMA处理句柄指针 */
__IO uint32_t ErrorCode; /* DAC错误代码 */
} DAC_HandleTypeDef;
从该结构体看到该函数并没有设置任何DAC相关寄存器,即没有对DAC进行任何配置,它只是HAL库提供用来在软件上初始化DAC,为后面HAL库操作DAC做好准备。 函数返回值: HAL_StatusTypeDef枚举类型的值。 注意事项: DAC的MSP初始化函数HAL_DAC_MspInit,该函数声明如下: void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac); 2. HAL_DAC_ConfigChannel函数 DAC 的通道参数初始化函数,其声明如下: HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel); 函数描述: 该函数用来配置DAC通道的触发类型以及输出缓冲。 函数形参: 形参1是DAC_HandleTypeDef结构体类型指针变量。 形参2是DAC_ChannelConfTypeDef结构体类型指针变量,其定义如下:
typedef struct
{
uint32_t DAC_SampleAndHold; /* 设置是否使能低功耗模式,即采样和保持模式 */
uint32_t DAC_Trigger; /* DAC触发源的选择 */
uint32_t DAC_OutputBuffer; /* 启用或者禁用DAC通道输出缓冲区 */
uint32_t DAC_ConnectOnChipPeripheral; /* 指定DAC输出是否连接到片上外设 */
uint32_t DAC_UserTrimming; /* 设置DAC的校准方式,采用出厂模式还是用户模式 */
uint32_t DAC_TrimmingValue; /* 设置用户校准模式的偏移值 */
DAC_SampleAndHoldConfTypeDef DAC_SampleAndHoldConfig; /* 设置采样保持具体参数 */
} DAC_ChannelConfTypeDef;
形参3用于选择要配置的通道,可选择DAC_CHANNEL_1或者DAC_CHANNEL_2。 函数返回值: HAL_StatusTypeDef枚举类型的值。 3. HAL_DAC_Start函数 使能启动DAC转换通道函数,其声明如下: HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel); 函数描述: 使能启动DAC转换通道。 函数形参: 形参1是DAC_HandleTypeDef结构体类型指针变量。 形参2用于选择要启动的通道,可选择DAC_CHANNEL_1或者DAC_CHANNEL_2。 函数返回值: HAL_StatusTypeDef枚举类型的值。 4. HAL_DAC_SetValue函数 DAC的通道输出值函数,其声明如下: HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data); 函数描述: 配置DAC的通道输出值。 函数形参: 形参1是DAC_HandleTypeDef结构体类型指针变量。 形参2用于选择要输出的通道,可选择DAC_CHANNEL_1或者DAC_CHANNEL_2。 形参3用于指定数据对齐方式。 形参4设置要加载到选定数据保存寄存器中的数据。 函数返回值: HAL_StatusTypeDef枚举类型的值。 5. HAL_DAC_GetValue函数 DAC读取通道输出值函数,其声明如下: uint32_t HAL_DAC_GetValue(DAC_HandleTypeDef hdac, uint32_t Channel); 函数描述: 获取所选DAC通道的最后一个数据输出值。 函数形参: 形参1是DAC_HandleTypeDef结构体类型指针变量。 形参2用于选择要读取的通道,可选择DAC_CHANNEL_1或者DAC_CHANNEL_2。 函数返回值: 获取到的输出值。 DAC输出配置步骤 1)开启DACx和DAC通道对应的IO时钟,并配置该IO为模拟功能 首先开启DACx的时钟,然后配置GPIO为模拟模式。本实验我们默认用到DAC1通道1,对应IO是PA4,它们的时钟开启方法如下: __HAL_RCC_DAC12_CLK_ENABLE (); / 使能DAC1时钟 / __HAL_RCC_GPIOA_CLK_ENABLE(); / 开启GPIOA时钟 */ 2)初始化DACx 通过HAL_DAC_Init函数来设置需要初始化的DAC。该函数并没有设置任何DAC相关寄存器,也就是说没有对DAC进行任何配置,它只是HAL库提供用来在软件上初始化DAC。 注意:该函数会调用HAL_DAC_MspInit函数来存放DAC和对应通道的IO时钟使能和初始化IO等代码。 3)配置DAC通道并启动DA转换器 在HAL库中,通过HAL_DAC_ConfigChannel函数来设置配置DAC的通道,根据需求设置触发类型以及输出缓冲。 配置好DAC通道之后,通过HAL_DAC_Start函数启动DA转换器。 4)设置DAC的输出值 通过HAL_DAC_SetValue函数设置DAC的输出值。 34.2.3.2 程序流程图
图34.2.3.2.1 DAC输出实验程序流程图 34.2.3.3 程序解析 这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。DAC驱动源码包括两个文件:dac.c和dac.h。 dac.h文件只有一些声明,下面直接开始介绍dac.c的程序,首先是DAC初始化函数。
/**
* @brief DAC初始化函数
* @note 本函数支持DAC1_OUT1/2通道初始化
* DAC的输入时钟来自APB1, 时钟频率=120Mhz=8.3ns
* DAC在输出buffer关闭的时候, 输出建立时间: tSETTLING = 2us (H750数据手册有写)
* 因此DAC输出的最高速度约为:500Khz, 以10个点为一个周期, 最大能输出50Khz左右的波形
*
* @param outx: 要初始化的通道. 1,通道1; 2,通道2
* @retval 无
*/
void dac_init(uint8_t outx)
{
DAC_ChannelConfTypeDef dac_ch_conf; /* DAC通道配置结构体 */
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_DAC12_CLK_ENABLE();/* 使能DAC12时钟,本芯片只有DAC1 */
__HAL_RCC_GPIOA_CLK_ENABLE();/* 使能DAC OUT1/2的IO口时钟(都在PA口,PA4/PA5) */
/* STM32单片机, 总是PA4=DAC1_OUT1, PA5=DAC1_OUT2 */
gpio_init_struct.Pin = (outx==1)? GPIO_PIN_4 : GPIO_PIN_5;
gpio_init_struct.Mode = GPIO_MODE_ANALOG; /* 模拟 */
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
g_dac_handle.Instance = DAC1; /* DAC1寄存器基地址 */
HAL_DAC_Init(&g_dac_handle); /* 初始化DAC */
dac_ch_conf.DAC_Trigger = DAC_TRIGGER_NONE; /* 不使用触发功能 */
dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;/* DAC1输出缓冲关闭 */
switch(outx)
{
case 1 :
/* DAC通道1配置 */
HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);
HAL_DAC_Start(&g_dac_handle, DAC_CHANNEL_1); /* 开启DAC通道2 */
break;
case 2 :
/* DAC通道1配置 */
HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_2);
HAL_DAC_Start(&g_dac_handle, DAC_CHANNEL_2); /* 开启DAC通道2 */
break;
default : break;
}
}
该函数主要调用HAL_DAC_Init和HAL_DAC_ConfigChannel函数初始化DAC,并调用HAL_DAC_Start函数使能DAC通道。HAL_DAC_Init函数会调用HAL_DAC_MspInit回调函数,该函数用于存放DAC和对应通道的IO时钟使能和初始化IO等代码。本实验为了让dac_init函数支持DAC的OUT1/2两个通道的初始化,就没有用到该函数。 下面是设置DAC通道1/2输出电压函数,其定义如下:
/**
* @brief 设置通道1/2输出电压
* @param outx: 1,通道1; 2,通道2
* @param vol : 0~3300,代表0~3.3V
* @retval 无
*/
void dac_set_voltage(uint8_t outx, uint16_t vol)
{
double temp = vol;
temp /= 1000;
temp = temp * 4096 / 3.3;
if (temp >= 4096)temp = 4095; /* 如果值大于等于4096, 则取4095 */
if (outx == 1) /* 通道1 */
{
/* 12位右对齐数据格式设置DAC值 */
HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp);
}
else /* 通道2 */
{
/* 12位右对齐数据格式设置DAC值 */
HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_2, DAC_ALIGN_12B_R, temp);
}
}
该函数实际就是将电压值转换为DAC输入值,形参1用于设置通道,形参2设置要输出的电压值,设置的范围:03300,代表03.3V。 最后在main函数里面编写如下代码:
int main(void)
{
uint16_t adcx;
float temp;
uint8_t t = 0;
uint16_t dacval = 0;
uint8_t key;
sys_cache_enable(); /* 打开L1-Cache */
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(240, 2, 2, 4); /* 设置时钟, 480Mhz */
delay_init(480); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
usmart_dev.init(240); /* 初始化USMART */
mpu_memory_protection(); /* 保护相关存储区域 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
key_init(); /* 初始化按键 */
adc_init(); /* 初始化ADC */
dac_init(1); /* 初始化DAC1_OUT1通道 */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "DAC TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 110, 200, 16, 16, "WK_UP:+ KEY1:-", RED);
lcd_show_string(30, 150, 200, 16, 16, "DAC VAL:", BLUE);
lcd_show_string(30, 170, 200, 16, 16, "DAC VOL:0.000V", BLUE);
lcd_show_string(30, 190, 200, 16, 16, "ADC VOL:0.000V", BLUE);
/* 初始值为0 */
HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0);
while (1)
{
t++;
key = key_scan(0); /* 按键扫描 */
if (key == WKUP_PRES)
{
if (dacval 200)dacval -= 200;
else dacval = 0;
HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R,
dacval);/* 输出减少200 */
}
/* WKUP/KEY1按下了,或者定时时间到了 */
if (t == 10 || key == KEY1_PRES || key == WKUP_PRES)
{
/* 读取前面设置DAC1_OUT1的值 */
adcx = HAL_DAC_GetValue(&g_dac_handle, DAC_CHANNEL_1);
lcd_show_xnum(94, 150, adcx, 4, 16, 0, BLUE); /* 显示DAC寄存器值 */
temp = (float)adcx * (3.3 / 4096); /* 得到DAC电压值 */
adcx = temp;
lcd_show_xnum(94, 170, temp, 1, 16, 0, BLUE); /* 显示电压值整数部分 */
temp -= adcx;
temp *= 1000;
lcd_show_xnum(110, 170, temp, 3, 16, 0X80, BLUE);/*显示电压值的小数部分*/
/* 得到ADC通道19的转换结果 */
adcx=adc_get_result_average(ADC_ADCX_CHY, 10);
temp = (float)adcx * (3.3 / 65536); /* 得到ADC电压值(adc是16bit的) */
adcx = temp;
lcd_show_xnum(94, 190, temp, 1, 16, 0, BLUE); /* 显示电压值整数部分 */
temp -= adcx;
temp *= 1000;
lcd_show_xnum(110, 190, temp, 3, 16, 0X80, BLUE);/*显示电压值的小数部分*/
LED0_TOGGLE(); /* LED0闪烁 */
t = 0;
}
delay_ms(10);
}
}
此部分代码,我们通过KEY_UP(WKUP按键)和KEY1(也就是上下键)来实现对DAC输出的幅值控制。按下KEY_UP增加,按KEY1减小。同时在LCD上面显示DHR12R1寄存器的值、DAC设置输出电压以及ADC采集到的DAC输出电压。 34.2.4 下载验证 下载代码后,可以看到LED0不停的闪烁,提示程序已经在运行了。LCD显示如下图所示:
图34.2.4.1 DAC输出实验测试图 验证试验前记得先通过跳线帽连接P3的ADC和DAC,然后我们可以通过按WK_UP按键,增加DAC输出的电压,这时ADC采集到的电压也会增大,通过按KEY1减小DAC输出的电压,这时ADC采集到的电压也会减小。 除此之外,我们还可以通过usmart调用dac_set_voltage函数,来直接设置DAC输出电压。
34.3 DAC输出三角波实验 本实验我们来学习使用如何让DAC输出三角波,DAC初始化部分还是用DAC输出实验的,所以做本实验的前提是先学习DAC输出实验。 34.3.1 DAC寄存器 本实验用到的寄存器在DAC输出实验都有介绍。 34.3.2 硬件设计
- 例程功能 使用DAC输出三角波,通过KEY0/KEY1两个按键,控制DAC1的通道1输出两种三角波,需要通过示波器接PA4进行观察。也可以通过usmart调用dac_triangular_wave函数,来控制输出哪种三角波。LED0闪烁,提示程序运行。
- 硬件资源 1)RGB灯 RED : LED0 - PB4 2)串口1(PA9/PA10连接在板载USB转串口芯片CH340上面) 3)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动) 4)独立按键 :KEY0 - PA1、KEY1 - PA15 5)DAC1 :通道1 - PA4
- 原理图 我们只需要把示波器的探头接到DAC1通道1(PA4)引脚,就可以在示波器上显示DAC输出的波形。PA4在P3多功能端口的DAC标志排针已经引出,硬件连接如图34.3.2.1所示: 在这里插入图片描述
图34.3.2.1 硬件连接示意图 34.3.3 程序设计 本实验用到的DAC的HAL库API函数前面都介绍过,具体调用情况请看程序解析部分。下面介绍DAC输出三角波的配置步骤。 DAC输出三角波配置步骤 1)开启DACx和DAC通道对应的IO时钟,并配置该IO为模拟功能 首先开启DACx的时钟,然后配置GPIO为模拟模式。本实验我们默认用到DAC1通道1,对应IO是PA4,它们的时钟开启方法如下: __HAL_RCC_DAC12_CLK_ENABLE (); /* 使能DAC1时钟 / __HAL_RCC_GPIOA_CLK_ENABLE(); / 开启GPIOA时钟 */ 2)初始化DACx 通过HAL_DAC_Init函数来设置需要初始化的DAC。该函数并没有设置任何DAC相关寄存器,也就是说没有对DAC进行任何配置,它只是HAL库提供用来在软件上初始化DAC。 注意:该函数会调用HAL_DAC_MspInit函数来存放DAC和对应通道的IO时钟使能和初始化IO等代码。 3)配置DAC通道并启动DA转换器 在HAL库中,通过HAL_DAC_ConfigChannel函数来设置配置DAC的通道,根据需求设置触发类型以及输出缓冲。 配置好DAC通道之后,通过HAL_DAC_Start函数启动DA转换器。 4)设置DAC的输出值 通过HAL_DAC_SetValue函数设置DAC的输出值。这里我们根据三角波的特性,创建了dac_triangular_wave函数用于控制输出三角波。 34.3.3.1 程序流程图
图34.3.3.1.1 DAC输出三角波实验程序流程图 34.3.3.2 程序解析 这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。DAC驱动源码包括两个文件:dac.c和dac.h。 dac.h文件只有一些声明,下面直接开始介绍dac.c的程序,本实验的DAC初始化我们还是用到dac_init函数,就添加了一个设置DAC_OUT1输出三角波函数,其定义如下:
/**
* @brief 设置DAC_OUT1输出三角波
* @note 输出频率 ≈ 1000 / (dt * samples) Khz, 不过在dt较小的时候,比如
小于5us时, 由于delay_us本身就不准了(调用函数,计算等都需要时间,延时
很小的时候,这些时间会影响到延时), 频率会偏小.
*
* @param maxval : 最大值(0 < maxval < 4096), (maxval + 1)必须大于等于samples/2
* @param dt : 每个采样点的延时时间(单位: us)
* @param samples: 采样点的个数, samples必须小于等于(maxval + 1) * 2 ,
且maxval不能等于0
* @param n : 输出波形个数,0~65535
*
* @retval 无
*/
void dac_triangular_wave(uint16_t maxval,
uint16_t dt, uint16_t samples, uint16_t n)
{
uint16_t i, j;
float incval; /* 递增量 */
float Curval; /* 当前值 */
if((maxval + 1)
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?