文章目录

  • DAC
    • DAC_CTL 控制寄存器
  • 定时器
    • TIMERx_CTL1 控制寄存器
    • 改变波形频率
  • DMA
    • DMA和外设配合
    • DMA_CHxCNT计数寄存器
  • 波形曲线
  • 总结
  • 源码

DAC

如下面框图所示,使能外部触发后(通过设置 DAC_CTL 寄存器的 DTENx 位), 当已经选择的触发事件发
生, DAC 保持数据(DACx_DH)会被转移到 DAC 数据输出寄存器(DACx_DO),经过一段时间之后,模拟输出变得有效。DAC引脚上的模拟输出电压DACoutput=VREF×DAC_DO/4096。

对于12位的DAC保持数据(DACx_DH),可以通过对DACx_R12DH、DACx_L12DH和DACx_R8DH中的任意一个寄存器写入数据来配置。

在外部触发使能的情况下,通过设置DAC_CTL寄存器的DDMAENx位来使能DMA请求。当有外部硬件触发的时候(不是软件触发),则产生一个DMA请求。

DAC_CTL 控制寄存器

名称 描述
DWBW0[3:0] DAC0 噪声波位宽
DDMAEN0 DAC0 DMA 使能
DWM0[1:0] DAC0 噪声波模式
DTSEL0[2:0] DAC0 触发选择
DBOFF0 DAC0 输出缓冲区
DEN0 DAC0 使能
DTEN0 DAC0 触发使能

配置DAC其实还是配置的上面这些东西,只不过,代码里面是调用了固件库函数来配的。

其中在DAC0外部触发使能(DTEN0=1)的情况下,DAC0外部触发源选择TIMER6 TRGO。

/*DAC通道输出配置,定时器6触发,不开启输出缓存*/
static void sin_adc_channel_config(void)
{//DAC外设复位dac_deinit();/* DAC触发禁能 */dac_trigger_disable(SIN_DAC);//DAC噪声波模式选择dac_wave_mode_config(SIN_DAC, DAC_WAVE_DISABLE);//DAC输出缓冲区禁能dac_output_buffer_disable(SIN_DAC);/* DAC触发源的选择*/dac_trigger_source_config(SIN_DAC,DAC_TRIGGER_T6_TRGO);/* DAC的DMA功能使能 */dac_dma_enable(SIN_DAC);/* DAC触发使能 */dac_trigger_enable(SIN_DAC);/* DAC使能 */dac_enable(SIN_DAC);
}

定时器

选用基本定时器TIM6触发DAC。

如下面框图所示,TIMER_CK驱动计数器预分频器,预分频值由TIMERx_PSC寄存器确定,TIMER_CK经过预分频器产生PSC_CLK。向上计数模式下,计数器从0开始向上连续计数到自动加载值(在TIMERx_CAR寄存器中),然后,重新从0开始向上计数并产生上溢事件。此时,如果TIMERx_SWEVG寄存器的UPG位置1,计数值会被清0,并产生更新事件。发生更新事件时,所有的寄存器(重复计数器,自动重载寄存器,预分频寄存器)都将被更新。

TIMERx_CTL1 控制寄存器

其中MMC[2:0]位控制TRGO信号的选择,使用timer_master_output_trigger_source_select函数,主模式控制器选择更新事件作为TRGO。

使用timer_update_event_enable函数,将TIMERx_SWEVG寄存器的UPG位置1,那么定时器产生上溢事件时会产生更新事件,然后触发TIMERx_TRGO。进而触发DAC。

 //定时器主输出触发源选择timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定时器更新事件使能timer_update_event_enable(SIN_TIM);

改变波形频率

这里面,设置不同的定时周期,会改变输出波形的频率。
按照下面这样设置,最终会得到4KHZ的正弦波。

/*TIMx触发配置*/
void sin_timx_trigger_function_config(void)
{timer_parameter_struct timer_initpara;rcu_periph_clock_enable(SIN_TIM_CLK);timer_deinit(SIN_TIM);/* TIMER6 configuration */timer_initpara.prescaler         = 1-1;//预分频timer_initpara.counterdirection  = TIMER_COUNTER_UP;//向上计数timer_initpara.period            = 225-1;//定时周期timer_init(SIN_TIM,&timer_initpara);//定时器主输出触发源选择timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定时器更新事件使能timer_update_event_enable(SIN_TIM);
}

DMA

DMA控制器提供了一种硬件的方式,在外设和存储器之间或者存储器和存储器之间传输数据。无需CPU的介入,使CPU可以专注在处理其他系统功能上。

DMA传输 ,从源地址读取数据后,将读取的数据存储到目的地址。

AHB从接口配置DMA,AHB主接口进行数据传输,仲裁器进行DMA请求的优先级管理。

dma_parameter_struct结构体:

名称 描述
periph_addr 外设基地址
periph_width 外设数据传输宽度
memory_addr 存储器基地址
memory_width 存储器数据传输宽度
number DMA通道数据传输数量
priority DMA通道传输软件优先级
periph_inc 外设地址生成算法模式
memory_inc 存储器地址生成算法模式
direction DMA通道数据传输方向

初始化,设定上面结构体的值,其实还是对DMA_CHxCTL寄存器的一些设置。设置传输方向为从存储器读出并写入外设。

存储器和外设都独立的支持两种地址生成算法:固定模式和增量模式。寄存器DMA_CHxCTL的PNAGA和MNAGA位用来设置存储器和外设的地址生成算法,固定模式中,地址一直固定为初始化的基地址,增量模式中,下一次传输数据的地址是当前地址加1(或2、4,取决于数据传输宽度) ,前面波形数组uint16_t Sine[POINT_NUM2]定义的是U16,所以设置的宽度也是16bit。

//DMA配置
static void sin_dma_config(void)
{dma_parameter_struct dma_init_struct;/* enable DMA CLK */rcu_periph_clock_enable(SIN_DMA_CLK);/* deinitialize DMA channel3(USART0 tx) */dma_deinit(SIN_DMA, SIN_DMA_CHANNEL);dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
//  dma_init_struct.memory_addr = ;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
//  dma_init_struct.number = ;
//  dma_init_struct.periph_addr = ;dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;dma_init(SIN_DMA, SIN_DMA_CHANNEL, &dma_init_struct);/* configure DMA mode 存储器到存储器DMA传输禁能*/dma_memory_to_memory_disable(SIN_DMA, SIN_DMA_CHANNEL);
}

DMA和外设配合

循环模式用来处理连续的外设请求,循环模式中,当每次DMA传输完成后,CNT值会被重新载入,且传输完成标志位会被置1。
DMA会一直响应外设的请求,直到通道使能位(DMA_CHxCTL寄存器的CHEN位)被清0。

当DMA控制器在同一时间接收到多个外设请求时,仲裁器将根据外设请求的优先级来决定响应哪一个外设请求。当通道具有相同的软件优先级时,编号低的通道优先级高。

多个外设请求被映射到同一个DMA 通道。这些请求信号在经过逻辑或后进入DMA。通过配置对应外设的寄存器,每个外设
的请求均可以独立的开启或关闭。DMA1各通道请求表如下,由于外设是DAC_CH0,所以选用DMA1的Channel2通道。

为了保证数据的有效传输, DMA控制器中引入了外设和存储器的握手机制。请求信号由外设发出,表明外设已经准备好发送或接收数据,应答信号由DMA控制器响应,表明DMA控制器已经发送AHB命令去访问外设。

DMA_CHxCNT计数寄存器

CNT[15:0],该寄存器表明还有多少数据等待被传输。一旦通道使能,该寄存器为只读的,并在每个DMA传输之后值减1。如果该寄存器的值为0,无论通道开启与否,都不会有数据传输。如果该通道工作在循环模式下,一旦通道的传输任务完成,该寄存器会被自动重装载为初始设置值。程序中,用dma_transfer_number_config函数配置该寄存器的值。

#define ARRAYNUM(arr_name)     (uint32_t)(sizeof(arr_name)/sizeof(*(arr_name)))
#define DAC0_R12DH_ADDRESS      ((uint32_t)0x40007408)
void sin_dma_function_config(void)
{   //DMAx的通道y的存储器基地址配置dma_memory_address_config(SIN_DMA,SIN_DMA_CHANNEL,(uint32_t)Sine);//配置DMAx通道y还有多少数据要传输dma_transfer_number_config(SIN_DMA,SIN_DMA_CHANNEL,ARRAYNUM(Sine));//DMAx的通道y的外设基地址配置dma_periph_address_config(SIN_DMA,SIN_DMA_CHANNEL,DAC0_R12DH_ADDRESS);//DMA循环模式开启dma_circulation_enable(SIN_DMA, SIN_DMA_CHANNEL);//DMA的通道使能dma_channel_enable(SIN_DMA, SIN_DMA_CHANNEL);
}

外设基地址配置:

DAC0_R12DH地址偏移: 0x08

DAC 基地址: 0x4000 7400

DAC0_R12DH地址:0x4000 7408

波形曲线

其中可以修改点数,使波形变得平滑;也可以修改波形幅值;也可以修改波形形状。

#! python3
#coding=utf-8import matplotlib.pyplot as plt
import numpy as np
import math#修改本变量可以更改点数,如16、32、64等
POINT_NUM = 120pi = math.pi#一个周期 POINT_NUM 个点
n = np.linspace(0,2*pi,POINT_NUM)#计算POINT_NUM个点的正弦值
a = map(math.sin,n)r =[]
for i in a:#调整幅值至在0~1区间i+=1       #按3.3V电压调整幅值#i*= 3.3/2   #求取dac数值,12位dac LSB = 3.3V/2**12 ri = round(i*2**12/3.3) #检查参数if ri >= 4095:ri = 4095#得到dac数值序列r.append( ri )print(list(map(int,r)))#写入序列到文件
with open("py_dac_sinWav.c",'w',encoding= 'gb2312') as f:print(list(map(int,r)),file= f)#绘图
plt.plot(n,r,"-o")
plt.show()

如果得到的值为a,那么(a/4096)*3.3就是实际输出的电压值。

uint16_t Sine[POINT_NUM2] = {1241, 1307, 1372, 1437, 1501, 1565, 1628, 1690, 1750, 1809, 1867, 1922, 1976, 2028, 2077, 2125, 2169, 2212, 2251, 2288, 2322, 2352, 2380, 2404, 2426, 2444, 2458, 2469, 2477, 2481, 2482, 2480, 2474, 2464, 2451, 2435, 2415, 2393, 2367, 2337, 2305, 2270, 2232, 2191, 2147, 2101, 2053, 2002, 1949, 1895, 1838, 1780, 1720, 1659, 1597, 1533, 1469, 1405, 1339, 1274, 1208, 1143, 1078, 1013, 949, 886, 824, 762, 703, 644, 588, 533, 480, 430, 381, 335, 292, 251, 213, 177, 145, 116, 90, 67, 47, 31, 18, 9, 3, 0, 1, 5, 13, 24, 39, 57, 78, 102, 130, 161, 195, 231, 271, 313, 358, 405, 455, 506, 560, 616, 673, 732, 793, 855, 917, 981, 1045, 1110, 1176, 1241
};

效果如下。

总结

1.使能TIM6触发DAC,其中,将TIMERx_SWEVG寄存器的UPG位置1,定时器产生上溢事件时会产生更新事件,主模式控制器选择更新事件作为TRGO。由于设置了DAC的DAC_CTL寄存器的DDMAENx位来使能DMA请求,当有外部硬件触发的时候,DAC则产生一个DMA请求。

3.使用DMA传输数据,从存储器读出数据并写入外设,也就是说,DMA从Sine数组的地址读数据,写到DAC0_R12DH寄存器里面。

2.触发事件发生, DAC保持数据(DACx_DH)会被转移到DAC数据输出寄存器(DACx_DO),经过一段时间之后,DAC引脚上的输出电压DACoutput=VREF×DAC_DO/4096。

4.总而言之,定时器从0开始向上连续计数到自动加载值,然后,重新从0开始向上计数并产生上溢事件,TIMERx_SWEVG寄存器的UPG位置1,计数值会被清0,并产生更新事件,主模式控制器选择更新事件作为TRGO,触发DAC,产生DMA请求,搬运数组的数据。由于DMA设置为循环模式,当每次DMA传输完成后,CNT值(待传输的数据个数)会被重新载入,DMA会一直响应外设的请求,如此循环往复,把波形曲线的值写到DAC0_R12DH寄存器里面,然后在DAC引脚上输出电压,DACoutput=VREF×DAC_DO/4096。

5.使用一个外设,看用户手册,可以知道外设大概都有哪些功能,要使用外设的某些功能都需要怎么配置寄存器。写程序的话,可能提供库函数,库函数就是把配置寄存器的那些代码给封装起来了,然后使用库函数把外设用起来就好了。

源码

GD32F307DAC输出波形-单片机文档类资源-CSDN文库
bsp_dac.c文件如下

main.c调用void sin_app(void)函数即可。

#include "systick.h"
#include "bsp_dac.h"
#define POINT_NUM 32
#define POINT_NUM2 120#define ARRAYNUM(arr_name)     (uint32_t)(sizeof(arr_name)/sizeof(*(arr_name)))
#define DAC0_R12DH_ADDRESS      ((uint32_t)0x40007408)#define DAC_OUT_VAL            (0x09B3)#define SIN_TIM                TIMER6
#define SIN_TIM_CLK     RCU_TIMER6#define SIN_DAC                        DAC0
#define SIN_DAC_CLK              RCU_DAC#define SIN_PIN            GPIO_PIN_4
#define SIN_GPIO_PORT      GPIOA
#define SIN_GPIO_CLK       RCU_GPIOA#define SIN_DMA                    DMA1
#define SIN_DMA_CLK            RCU_DMA1
#define SIN_DMA_CHANNEL    DMA_CH2uint16_t Sine12bit[POINT_NUM] = {1241, 1491, 1731, 1950, 2141, 2295, 2405, 2468, 2481, 2443, 2356, 2223, 2050, 1844, 1613, 1367, 1116,
870, 639, 433, 260, 127, 40, 2, 14, 77, 188, 342, 532, 752, 991, 1241
};
uint16_t Sine[POINT_NUM2] = {1241, 1307, 1372, 1437, 1501, 1565, 1628, 1690, 1750, 1809, 1867, 1922, 1976, 2028, 2077, 2125, 2169, 2212, 2251, 2288, 2322, 2352, 2380, 2404, 2426, 2444, 2458, 2469, 2477, 2481, 2482, 2480, 2474, 2464, 2451, 2435, 2415, 2393, 2367, 2337, 2305, 2270, 2232, 2191, 2147, 2101, 2053, 2002, 1949, 1895, 1838, 1780, 1720, 1659, 1597, 1533, 1469, 1405, 1339, 1274, 1208, 1143, 1078, 1013, 949, 886, 824, 762, 703, 644, 588, 533, 480, 430, 381, 335, 292, 251, 213, 177, 145, 116, 90, 67, 47, 31, 18, 9, 3, 0, 1, 5, 13, 24, 39, 57, 78, 102, 130, 161, 195, 231, 271, 313, 358, 405, 455, 506, 560, 616, 673, 732, 793, 855, 917, 981, 1045, 1110, 1176, 1241
};/*DAC引脚配置*/
static void sin_dac_gpio_config(void)
{/* enable the clock of peripherals */rcu_periph_clock_enable(SIN_GPIO_CLK);rcu_periph_clock_enable(SIN_DAC_CLK);rcu_periph_clock_enable(RCU_AF);/* once enabled the DAC, the corresponding GPIO pin is connected to the DAC converter automatically */gpio_init(SIN_GPIO_PORT, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, SIN_PIN);}/*DAC通道输出配置,定时器6触发,不开启输出缓存*/
static void sin_adc_channel_config(void)
{dac_deinit();/* configure the DAC0 */dac_trigger_disable(SIN_DAC);dac_wave_mode_config(SIN_DAC, DAC_WAVE_DISABLE);dac_output_buffer_disable(SIN_DAC);/* DAC触发源的选择*/dac_trigger_source_config(SIN_DAC,DAC_TRIGGER_T6_TRGO);/* DAC的DMA功能使能 */dac_dma_enable(SIN_DAC);/* DAC触发使能 */dac_trigger_enable(SIN_DAC);/* enable DAC0 */dac_enable(SIN_DAC);}
//DMA配置
static void sin_dma_config(void)
{dma_parameter_struct dma_init_struct;/* enable DMA CLK */rcu_periph_clock_enable(SIN_DMA_CLK);/* deinitialize DMA channel3(USART0 tx) */dma_deinit(SIN_DMA, SIN_DMA_CHANNEL);dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
//  dma_init_struct.memory_addr = ;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
//  dma_init_struct.number = ;
//  dma_init_struct.periph_addr = ;dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;dma_init(SIN_DMA, SIN_DMA_CHANNEL, &dma_init_struct);/* configure DMA mode */dma_memory_to_memory_disable(SIN_DMA, SIN_DMA_CHANNEL);
}void sin_config(void)
{//引脚配置sin_dac_gpio_config();//通道配置sin_adc_channel_config();//DMA配置sin_dma_config();
}void sin_dma_function_config(void)
{   //DMAx的通道y的存储器基地址配置dma_memory_address_config(SIN_DMA,SIN_DMA_CHANNEL,(uint32_t)Sine);//配置DMAx通道y还有多少数据要传输dma_transfer_number_config(SIN_DMA,SIN_DMA_CHANNEL,ARRAYNUM(Sine));//DMAx的通道y的外设基地址配置dma_periph_address_config(SIN_DMA,SIN_DMA_CHANNEL,DAC0_R12DH_ADDRESS);//DMA循环模式开启dma_circulation_enable(SIN_DMA, SIN_DMA_CHANNEL);//DMA的通道使能dma_channel_enable(SIN_DMA, SIN_DMA_CHANNEL);
}/*TIMx触发配置*/
void sin_timx_trigger_function_config(void)
{timer_parameter_struct timer_initpara;rcu_periph_clock_enable(SIN_TIM_CLK);timer_deinit(SIN_TIM);/* TIMER6 configuration */timer_initpara.prescaler         = 1-1;//预分频timer_initpara.counterdirection  = TIMER_COUNTER_UP;//向上计数timer_initpara.period            = 225-1;//定时周期timer_init(SIN_TIM,&timer_initpara);//定时器主输出触发源选择timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定时器更新事件使能timer_update_event_enable(SIN_TIM);
}/*操作函数*/
void sin_app(void)
{//*配置*/sin_config();//DMA功能配置sin_dma_function_config();// TIMER触发功能配置sin_timx_trigger_function_config();// TIMER启动timer_enable(SIN_TIM);}

bsp_dac.h文件

#include "gd32f30x.h"void sin_app(void);

GD32F307 DAC 输出波形相关推荐

  1. DAC输出波形的最大频率是多少?

    简 介: 对于信号与系统课程同学提出的关于DAC输出信号中的最大频率的讨论. 关键词: ADC,DAC,零阶保持,一阶保持 §01 DAC输出信号的最大频率 1.提问: 卓老师您好!抱歉这么晚打扰您, ...

  2. STM32的PWM与DAC输出波形

    使用STM32输出PWM波形 1.使用资料:野火开发板资料 <零死角玩转STM32> 2.PWM模式介绍 脉宽调制(PWM)基本原理:控制方式就是对逆变电路开关器件的通断进行控制,使输出端 ...

  3. 【STM32】HAL库 STM32CubeMX教程十---DAC

    前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...

  4. STM32配置DAC输出固定电压和方波

    STM32F103VCT6自带两个12位DAC,DAC的转换速度一直没有查到,网上有人说是1MHZ的频率,那就是1us了.ADC的转换时间在56MHZ工作频率下为1us,在72MHZ工作频率下为1.1 ...

  5. STM32F4 DAC

    国电临近,总结一下之前写过的一些程序和电路.时间不多,只能抽空写了,等闲的时候再一并写好,以飨读者. 数据手册里的 : TRGO:触发输出 TRGI:触发输入 STM32F103VCT6自带两个12位 ...

  6. STM32的DAC软件触发模式配置

    DAC软件触发模式配置   软件触发模式配置步骤如下,   DAC可以使用定时器外部触发,也可以软件触发. ①使能DAC时钟及GPIO的模拟复用时钟.   ②配置DAC电压输出的GPIO为DAC模拟复 ...

  7. 信号与系统2021年期末考试命题

    简 介: 本文是针对2021年春季学期信号与系统课程期末考试命题所做的准备工作. 关键词: 信号与系统,命题,期末考试 §00 命题说明 1.命题题型   本次命题是面向2021年本科"信号 ...

  8. 利用STM32F405RG制作pyBoard实验板

    ▌01 pyBoard实验板 1.pyBoard pyBoard是可以通过 MicroPython 进行编程的实验板.由于它板子不太适合在面包板上实验,主要原因是它太宽了,无法做到向 RaspBerr ...

  9. 基于FPGA实现DDS正弦波发生器

    名言:学无止境. 1 开发环境 操作系统:win7 开发软件:ISE14.7 硬件平台:Xilinx FPGA Spartan6 2 DDS简介 DDS(Direct Digital Synthesi ...

最新文章

  1. html 自动弹出框
  2. iOS UIView快速添加事件
  3. 破译“生命天书”20年
  4. Windows2008系统忘记密码的解决方法
  5. 【node节点版本管理器NVM,详解安装教程,建议收藏】
  6. php request time,php中time()与$_SERVER[REQUEST_TIME]用法区别分析
  7. Springboot2拦截器与文件上传
  8. iOS中的UIView的基本属性1
  9. 易语言 精易模块 网页_访问 获取显示验证码图片
  10. 第二阶段冲刺sprint计划会议
  11. 推荐一个Web前端程序员必须要吃透的书籍!
  12. 微信小程序——漂亮的步骤条(好看)
  13. epub格式电子书制作工具——ep…
  14. Win8调整笔记本亮度,数值有变化但无效果
  15. 14、pyspider框架
  16. Python科学计算:读取txt,csv,mat文件
  17. 同行动态:海隆软件96%销售额来自出口
  18. (转)禁止掉ORACLE 的XDB服务
  19. 六 计算机故障分析及处理,计算机系统故障分析与处理
  20. Reactor百万连接的并发

热门文章

  1. 带你理解beta分布
  2. python程序设计基础刘艳网课_智慧职教APPPython程序设计基础(九江职业技术学院)题目答案...
  3. 13.3 跳格子游戏
  4. 比较经典的位字段例题(颜色三原色)
  5. MongoDb之TTL索引
  6. java 回车表示_关于JAVA中回车符的认识
  7. Android 修改昵称
  8. 【金融量化】深度学习在金融中的研究热点以及应用
  9. XSCTF联合招新【真是阳间题】(MSIC+Crypto)
  10. git的GUI工具Sourcetree使用及命令行对比