DAC——输出正弦波

模拟技术

2347人已加入

描述

DAC——输出正弦波

26.1. DAC简介

DAC即数模转换模块,顾名思义,它的作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与ADC相反。 在常见的数字信号系统中,大部分传感器信号被化成数字信号,而ADC把电压模拟信号转换成易于计算机存储、处理的数字编码,然后将这些数字编码交给计算机进行处理处理, 由DAC生成的模拟电压常常用来驱动某些执行器件比如LED灯可以控制它的亮度,使人们易于感知。

RA6M5具有片上DAC外设,总共有两路DAC输出通道,每路的分辨率可配置为12位, 这两个通道之间互不影响,每个通道都可以使用ELC功能可外部触发或者进行与ADC单元1的同步转换。

26.1.1. DAC特性

  • 分辨率:12-bits
  • 输出通道:2 通道
  • 可设置模块停止状态降低功耗
  • DAC0 和 DAC1 可以通过一个事件信号输入来开启转换
  • 可通过以下方法减少 DAC 和 ADC 模块之间的干扰:
    • 同步D/A转换控制,使D/A转换数据的更新时间由ADC12(uint1)输入信号同步
    • 通过合理的控制DAC12的启动信号来减少干扰对D/A转换精度的影响

26.2. DAC的结构框图

RA6M5的DAC模块框图可见

示波器框图中的“12-bit D/A”是核心部件,整个DAC外设都是围绕着DA1通道和DA0通道展开的, 左上作为参考电源以及模拟转换输出,右边有着相应的控制寄存器、总线接口、和同步转换。

26.2.1. 参考电压

AVCC0引脚作为ADC12和DAC12的电源输入引脚,AVSS0引脚作为ADC12和DAC12的接地输入引脚。 VREFH引脚作为DAC12的模拟参考高电压电源引脚。 VREFL引脚作为DAC12的模拟参考低电压引脚。

我们分别把它们接入到电源的正负两级,可以得到DAC的输出电压范围为:0-3.3V。 如果想让输出的电压范围变宽,可以在外部加一个电压调节电路,把0~3.3V的DAC输出抬升到特定的范围即可。

在电路设计的时候不增加磁珠和电容接入到DAC12电源电路,会使得我们输出的电压不稳甚至输出的不是我们想要的电压, 这个时候我们可以在电路上增加磁珠和电容来减少干扰,从而优化我们的DAC比较电压源从而使其输出稳定。

26.2.2. 触发源

我们可以设置软件来触发DAC、或者通过使用ELC进行触发、甚至我们还可以使用外部中断进行触发。 最终我们的目的是为了使得DACR.DAOEn(n=0,1)位被置1, 我们可以编写相应的寄存器控制代码以至于我们可以使用不同的方式进行触发。

示波器

当设置DACR中的DAOEn位(n = 0,1)为1时,启用DAC12并输出转换结果。 当设置DACR中的DAOEn位(n = 0,1)为0时,关闭DAC输出转换。

下面是使用软件触发方式来使能DAC的代码:

/**
* @brief  软件使能并输出电压
* @param  输入DAC模块
* @retval 无
*/
void trigger_dac(dac_ctrl_t * p_api_ctrl)
{
   dac_instance_ctrl_t * p_ctrl = (dac_instance_ctrl_t *) p_api_ctrl;
   p_ctrl->p_reg->DACR_b.DAOE0 = 1U;   //使能DAC通道一使其输出相应电压
   //p_ctrl->p_reg->DACR_b.DAOE1 = 1U;   //使能DAC通道二使其输出相应电压
}

26.2.3. DAC数据寄存器

DADRn(D/A数据转换寄存器) :

DADRn寄存器是一个16位的读/写寄存器,它存储用于D/A转换的数据。 虽然DADRn数据寄存器有16位数据,但是我们只用到了前面的12位,而后四位没有用到。 我们还可以通过DADPR.DPSEL位进行设置12位的数据设置为左对齐或右对齐的数据格式。

示波器当我们设置的触发源被启动时,DADRn中的值就会被转换并输出到模拟输出引脚上。 之后每当我们改变DADRn中的数值时,就可以改变输出的模拟电压。

电压转换公式 :

如果我们直接通过输入一个12位的数字值,之后进行对DAC的触发源进行操作时,那么我们对软件的可操作性就比较差, 这个时候我们可以通过对软件代码优化使得我们更容易操作和控制电压,以下就是12位的数字值与电压之间的转换公式:

示波器通过上面的公式我们知道(设定的数值/4096)x(基准电压)等于需要设定的电压, X对应着需要设定的电压,Y为我们最终需要设定的数值,那么会有这么一个等式成立: Y/2^12 * 3.3 = X => X / 3.3 * 2^12 = Y。 通过这个公式我们就可以知道设置的D/A转换电压是多少,我们将上面的公式写成如下的函数。 其中set_voltage为我们需要设置的电压,dac_date为我们需要输入到D/A数据转换寄存器的数据。

/**
* @brief  设置当前的电压3.3V
* @param  需要控制的电压
* @retval 无
*/
void dac_Set(double voltage)
{
   uint16_t dac_date;
   dac_date = (uint16_t)4095*((voltage)/3.3f);
   R_DAC_Write(DAC.p_ctrl, dac_date);
}

26.2.4. 转换的过程

在转换的过程中我们想要停止DAC转换的话,只需要将DACR.DAOEn(n=0,1)位给置0。

  1. 第一步在DADPR寄存器中设置我们想要转换的数据格式
  2. 触发使能寄存器,使得DAC使能寄存器DACR.DAOEn(n=0,1),以开始数模转换转换的结果将在一段时间t过后从输出引脚DA0上输出。 如果使能寄存器一直为1的话,DAC将一直转换输出,直到将DAC使能寄存器DACR.DAOEn(n=0,1)位设置0。
  3. 若在转换的过程中,想要改变DAC模拟输出的数值的时候,我们需要将一个值写入到数据寄存器DADRn(n=0,1)中,转换的结果将在一段时间t过后从输出引脚DAn(n=0,1)上输出。

26.2.5. 同步转换

通过同步转换我们可以使得ADC的单元一和DAC进行同步转换, 我们通过两个寄存器来控制这一过程,这两个寄存器分别为:我们通过两个寄存器来控制这一过程这两个寄存器分别为:同步单元选择寄存器(DAADUSR寄存器)和 同步使能转换寄存器(DAADSCR寄存器)。

DAADSCR寄存器

如果我们使用ELC事件链接控制器来控制的话,我们就不能够使能DAADSCR寄存器。 将DAADST位设置为0,允许DADRn寄存器值随时转换为模拟数据。 将DAADST位设置为1,允许D/A转换与同步D/A转换同步,使来自ADC12的输入信号同步(单元1)。 使用此位直到DADC12(单元1)完成A/D转换才开始D/A转换,即使DADRn寄存器被改变。

DAADUSR寄存器

DAADUSR寄存器选择ADC12单元一进行D/A和A/D同步转换。 将AMADSEL1位设置为1,选择ADC单元1作为DAC的同步单元。 将AMADSEL1位设置为0,不选择ADC单元同步单元。

26.3. 生成正弦波数据表

要输出正弦波,实质是要控制DAC以v=sin(t)的正弦函数关系输出电压,其中v为电压输出,t为时间。

而由于模拟信号连续而数字信号是离散的,所以使用DAC产生正弦波时,只能按一定时间间隔输出正弦曲线上的点,在该时间段内输出相同 的电压值,若缩短时间间隔,提高单个周期内的输出点数,可以得到逼近连续正弦波的图形,见 图26_3,若在外部电路加上适当的电容滤波,可得到更完美的图形。

示波器图 26‑3 DAC按点输出正弦波数据(左:32个点,右:128个点)

由于正弦曲线是周期函数,所以只需要得到单个周期内的数据后按周期重复即可,而单个周期内取样输出的点数又是有限的,所以为了得到呈v=sin(t)函数关系电压值的数据通常不会实时计算获取,而是预先计算好函数单个周期内的电压数据表,并且转化成以DAC寄存器表示的值。

如sin函数值的范围为[-1: +1],而RA6M5的DAC输出电压范围为[0~3.3]V,按12位DAC分辨率表示的方法,可写入寄存器的最大值为2^12^ = 4096,即范围为[0:4096]。 所以,实际输出时,会进行如下处理:

  1. 抬升sin函数的输出为正值:v = sin(t)+1 ,此时,v的输出范围为[0:2];
  2. 扩展输出至DAC的全电压范围: v = 3.3*(sin(t)+1)/2 ,此时,v的输出范围为[0:3.3],正是DAC的电压输出范围,扩展至全电压范围可以充分利用DAC的分辨率;
  3. 把电压值以DAC寄存器的形式表示:Reg_val = 2 ^12^ /3.3 * v = 2 ^11^ *(sin(t)+1),此时,存储到DAC寄存器的值范围为[0:4095];
  4. 实践证明,在sin(t)的单个周期内,取32个点进行电压输出已经能较好地还原正弦波形,所以在t∈[0:2π]区间内等间距根据上述Reg_val公式运算得到32个寄存器值,即可得到正弦波表;
  5. 控制DAC输出时,每隔一段相同的时间从上述正弦波表中取出一个新数据进行输出,即可输出正弦波。 改变间隔时间的单位长度,可以改变正弦波曲线的周期。

为方便起见,我们使用了Python和Matlab脚本制作正弦波表,脚本的代码存储在本工程的目录下,感兴趣可以打开文件查看,以下列出Python脚本代码,见代码清单 26‑2。

代码清单 26‑2 制作正弦波数据表的python脚本(工程目录下的sinWave.py文件) [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter26/chapter26.html#id11 " 永久链接至代码")

#! python3
#coding=utf-8

"""
Python版本:3.x
外部库:matplotlib1.5.3、numpy1.11.2

运行方式:
在命令行中输入:python sinWave.py

运行结果:
命令行中会打印计算得的各点数据,
在当前目录下会生成py_dac_sinWav.c文件,包含上述数据,
并且会弹出描绘曲线的对话框。
"""

import matplotlib.pyplot as plt
import numpy as np
import math

#修改本变量可以更改点数,如16、32、64等
POINT_NUM = 32

pi = 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()

Python脚本的实现原理就是前面介绍的正弦波数据表的制作过程,运行后,该脚本把得到的正弦波表数据输出到目录下的py_dac_sinWav.c文件中,见代码清单 26‑3,并且根据取样点描绘出示意图,见图 26‑4。 Matlab脚本原理相同,此处不再列出,实际上使用C语言也能制作正弦波表,只是画图不方便而已。

代码清单 26‑3 生成的正弦波数据表 [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter26/chapter26.html#id12 "永久链接至代码")

[2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668,
3382, 3042, 2661, 2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127,
310, 564, 878, 1240, 1636, 2048]

示波器图 26‑4 python 脚本根据正弦波表描绘的曲线图

26.4. DAC程序设计

26.4.1. 硬件设计

我们使用引出来的排针P015或者P014

示波器DAC引脚 [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter26/chapter26.html#id24 "永久链接至表格")| DAC通道0 | P014 |
| ------------------ | ------ |
| DAC通道1 | P015 |

26.4.2. 软件设计

26.4.2.1. 新建工程

e2 studio :新建一个的RA6M5工程, 然后将工程文件夹重命名为 “25_DAC” ,之后将其加入到我们的e2 studio工作空间中。

Keil :我们可以拷贝一份我们之前的Keil工程模板, 然后将工程文件夹重命名为 “25_DAC” ,并进入该文件夹双击里面的 Keil 工程文件,打开该工程。

26.4.2.2. FSP配置

我们先打开e2 studio软件里面的 Smart Configurator 配置FSP。 双击 configuration.xml 打开配置界面: 然后点开依次点击 Stacks -> New Stack -> Analog -> DAC(r_dac) 来配置DAC模块。

示波器DAC页面的属性介绍

示波器DAC 属性介绍 [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter26/chapter26.html#id25 "永久链接至表格")| Name | 名称 |
| - | - |
| ---------------------- |

渠道 通道
与 ADC 同步 同步与ADC
日期格式 数据格式
输出放大器 使能DAC输出放大器
内部输出 内部输出
ELC 触发源 ELC 触发

配置完成之后可以按下快捷键“Ctrl + S”保存, 最后点右上角的 “Generate Project Content” 按钮,让软件自动生成配置代码即可。

26.4.2.3. DAC初始化

/**
* @brief  初始化DAC
* @param  无
* @retval 无
*/
void dac_Init()
{
    R_DAC_Open(DAC.p_ctrl, DAC.p_cfg);
    R_DAC_Start(DAC.p_ctrl);
}
  1. R_DAC_Open()配置单个 DAC 通道,启动通道,并提供用于 DAC API 写入和关闭函数的句柄。
  2. R_DAC_Start()启动 D/A 转换输出。

26.4.2.4. DAC设置电压

/**
* @brief  设置当前的电压3.3V
* @param  需要控制的电压
* @retval 无
*/
void dac_Set(double voltage)
{
    uint16_t dac_date;
    dac_date = (uint16_t)4095*((voltage)/3.3f);
    R_DAC_Write(DAC.p_ctrl, dac_date);
}

通过电压转换公式将输入的模拟量转换为数值量,输入到R_DAC_Write()函数里, R_DAC_Write()会将数据写入到 D/A 转换器里。

26.4.2.5. DAC输出正弦波

/*py生成的正弦波变量*/
int var[] = {2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668,
          3382, 3042, 2661, 2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127,
          310, 564, 878, 1240, 1636, 2048};

/**
* @brief  生成正弦波波形
* @param  输入可以调节波形的宽度
* @retval 
*/
void dac_Circle(uint32_t timer)
{
    for(int i = 0 ; i < (sizeof(var)/sizeof(var[0])); i++)
    {
        R_DAC_Write(DAC.p_ctrl, var[i]);
        R_BSP_SoftwareDelay(timer, BSP_DELAY_UNITS_MILLISECONDS);
    }
}

通过轮循的方式将之前python生成的正弦波数据输入到R_DAC_Write()函数里面, 并且延时一段时间。 而延时时间就是我们输入到函数里面的数值, 通过改变这一数值我们就可以调节正弦波的周期以及频率。

26.4.2.6. 主函数

void hal_entry(void)
{
   dac_Init(); //DAC初始化
      while(1)
      {
         dac_Circle(100);  //正弦波函数
      }

#if BSP_TZ_SECURE_BUILD
   /* Enter non-secure code */
   R_BSP_NonSecureEnter();
#endif
}

26.4.3. 下载验证

用USB线连接开发板的“USB转串口”接口跟电脑,把编译好的程序下载到开发板,使用示波器测量P014的引脚可看到正弦波形(示波器使用x10倍档测量更加准确),见图 26‑6,注意观察图中示波器测量出的频率值和电压峰值。

示波器

图 26‑6 使用示波器测量出的电压波形

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

全部0条评论

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

×
20
完善资料,
赚取积分