DAC——輸出正弦波
26.1. DAC簡(jiǎn)介
DAC即數(shù)模轉(zhuǎn)換模塊,顧名思義,它的作用就是把輸入的數(shù)字編碼,轉(zhuǎn)換成對(duì)應(yīng)的模擬電壓輸出,它的功能與ADC相反。 在常見的數(shù)字信號(hào)系統(tǒng)中,大部分傳感器信號(hào)被化成數(shù)字信號(hào),而ADC把電壓模擬信號(hào)轉(zhuǎn)換成易于計(jì)算機(jī)存儲(chǔ)、處理的數(shù)字編碼,然后將這些數(shù)字編碼交給計(jì)算機(jī)進(jìn)行處理處理, 由DAC生成的模擬電壓常常用來(lái)驅(qū)動(dòng)某些執(zhí)行器件比如LED燈可以控制它的亮度,使人們易于感知。
RA6M5具有片上DAC外設(shè),總共有兩路DAC輸出通道,每路的分辨率可配置為12位, 這兩個(gè)通道之間互不影響,每個(gè)通道都可以使用ELC功能可外部觸發(fā)或者進(jìn)行與ADC單元1的同步轉(zhuǎn)換。
26.1.1. DAC特性
- 分辨率:12-bits
- 輸出通道:2 通道
- 可設(shè)置模塊停止?fàn)顟B(tài)降低功耗
- DAC0 和 DAC1 可以通過(guò)一個(gè)事件信號(hào)輸入來(lái)開啟轉(zhuǎn)換
- 可通過(guò)以下方法減少 DAC 和 ADC 模塊之間的干擾:
- 同步D/A轉(zhuǎn)換控制,使D/A轉(zhuǎn)換數(shù)據(jù)的更新時(shí)間由ADC12(uint1)輸入信號(hào)同步
- 通過(guò)合理的控制DAC12的啟動(dòng)信號(hào)來(lái)減少干擾對(duì)D/A轉(zhuǎn)換精度的影響
26.2. DAC的結(jié)構(gòu)框圖
RA6M5的DAC模塊框圖可見
框圖中的“12-bit D/A”是核心部件,整個(gè)DAC外設(shè)都是圍繞著DA1通道和DA0通道展開的, 左上作為參考電源以及模擬轉(zhuǎn)換輸出,右邊有著相應(yīng)的控制寄存器、總線接口、和同步轉(zhuǎn)換。
26.2.1. 參考電壓
AVCC0引腳作為ADC12和DAC12的電源輸入引腳,AVSS0引腳作為ADC12和DAC12的接地輸入引腳。 VREFH引腳作為DAC12的模擬參考高電壓電源引腳。 VREFL引腳作為DAC12的模擬參考低電壓引腳。
我們分別把它們接入到電源的正負(fù)兩級(jí),可以得到DAC的輸出電壓范圍為:0-3.3V。 如果想讓輸出的電壓范圍變寬,可以在外部加一個(gè)電壓調(diào)節(jié)電路,把0~3.3V的DAC輸出抬升到特定的范圍即可。
在電路設(shè)計(jì)的時(shí)候不增加磁珠和電容接入到DAC12電源電路,會(huì)使得我們輸出的電壓不穩(wěn)甚至輸出的不是我們想要的電壓, 這個(gè)時(shí)候我們可以在電路上增加磁珠和電容來(lái)減少干擾,從而優(yōu)化我們的DAC比較電壓源從而使其輸出穩(wěn)定。
26.2.2. 觸發(fā)源
我們可以設(shè)置軟件來(lái)觸發(fā)DAC、或者通過(guò)使用ELC進(jìn)行觸發(fā)、甚至我們還可以使用外部中斷進(jìn)行觸發(fā)。 最終我們的目的是為了使得DACR.DAOEn(n=0,1)位被置1, 我們可以編寫相應(yīng)的寄存器控制代碼以至于我們可以使用不同的方式進(jìn)行觸發(fā)。
當(dāng)設(shè)置DACR中的DAOEn位(n = 0,1)為1時(shí),啟用DAC12并輸出轉(zhuǎn)換結(jié)果。 當(dāng)設(shè)置DACR中的DAOEn位(n = 0,1)為0時(shí),關(guān)閉DAC輸出轉(zhuǎn)換。
下面是使用軟件觸發(fā)方式來(lái)使能DAC的代碼:
/**
* @brief 軟件使能并輸出電壓
* @param 輸入DAC模塊
* @retval 無(wú)
*/
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通道一使其輸出相應(yīng)電壓
//p_ctrl->p_reg->DACR_b.DAOE1 = 1U; //使能DAC通道二使其輸出相應(yīng)電壓
}
26.2.3. DAC數(shù)據(jù)寄存器
DADRn(D/A數(shù)據(jù)轉(zhuǎn)換寄存器) :
DADRn寄存器是一個(gè)16位的讀/寫寄存器,它存儲(chǔ)用于D/A轉(zhuǎn)換的數(shù)據(jù)。 雖然DADRn數(shù)據(jù)寄存器有16位數(shù)據(jù),但是我們只用到了前面的12位,而后四位沒(méi)有用到。 我們還可以通過(guò)DADPR.DPSEL位進(jìn)行設(shè)置12位的數(shù)據(jù)設(shè)置為左對(duì)齊或右對(duì)齊的數(shù)據(jù)格式。
當(dāng)我們?cè)O(shè)置的觸發(fā)源被啟動(dòng)時(shí),DADRn中的值就會(huì)被轉(zhuǎn)換并輸出到模擬輸出引腳上。 之后每當(dāng)我們改變DADRn中的數(shù)值時(shí),就可以改變輸出的模擬電壓。
電壓轉(zhuǎn)換公式 :
如果我們直接通過(guò)輸入一個(gè)12位的數(shù)字值,之后進(jìn)行對(duì)DAC的觸發(fā)源進(jìn)行操作時(shí),那么我們對(duì)軟件的可操作性就比較差, 這個(gè)時(shí)候我們可以通過(guò)對(duì)軟件代碼優(yōu)化使得我們更容易操作和控制電壓,以下就是12位的數(shù)字值與電壓之間的轉(zhuǎn)換公式:
通過(guò)上面的公式我們知道(設(shè)定的數(shù)值/4096)x(基準(zhǔn)電壓)等于需要設(shè)定的電壓, X對(duì)應(yīng)著需要設(shè)定的電壓,Y為我們最終需要設(shè)定的數(shù)值,那么會(huì)有這么一個(gè)等式成立: Y/2^12 * 3.3 = X => X / 3.3 * 2^12 = Y。 通過(guò)這個(gè)公式我們就可以知道設(shè)置的D/A轉(zhuǎn)換電壓是多少,我們將上面的公式寫成如下的函數(shù)。 其中set_voltage為我們需要設(shè)置的電壓,dac_date為我們需要輸入到D/A數(shù)據(jù)轉(zhuǎn)換寄存器的數(shù)據(jù)。
/**
* @brief 設(shè)置當(dāng)前的電壓3.3V
* @param 需要控制的電壓
* @retval 無(wú)
*/
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. 轉(zhuǎn)換的過(guò)程
在轉(zhuǎn)換的過(guò)程中我們想要停止DAC轉(zhuǎn)換的話,只需要將DACR.DAOEn(n=0,1)位給置0。
- 第一步在DADPR寄存器中設(shè)置我們想要轉(zhuǎn)換的數(shù)據(jù)格式
- 觸發(fā)使能寄存器,使得DAC使能寄存器DACR.DAOEn(n=0,1),以開始數(shù)模轉(zhuǎn)換轉(zhuǎn)換的結(jié)果將在一段時(shí)間t過(guò)后從輸出引腳DA0上輸出。 如果使能寄存器一直為1的話,DAC將一直轉(zhuǎn)換輸出,直到將DAC使能寄存器DACR.DAOEn(n=0,1)位設(shè)置0。
- 若在轉(zhuǎn)換的過(guò)程中,想要改變DAC模擬輸出的數(shù)值的時(shí)候,我們需要將一個(gè)值寫入到數(shù)據(jù)寄存器DADRn(n=0,1)中,轉(zhuǎn)換的結(jié)果將在一段時(shí)間t過(guò)后從輸出引腳DAn(n=0,1)上輸出。
26.2.5. 同步轉(zhuǎn)換
通過(guò)同步轉(zhuǎn)換我們可以使得ADC的單元一和DAC進(jìn)行同步轉(zhuǎn)換, 我們通過(guò)兩個(gè)寄存器來(lái)控制這一過(guò)程,這兩個(gè)寄存器分別為:我們通過(guò)兩個(gè)寄存器來(lái)控制這一過(guò)程這兩個(gè)寄存器分別為:同步單元選擇寄存器(DAADUSR寄存器)和 同步使能轉(zhuǎn)換寄存器(DAADSCR寄存器)。
DAADSCR寄存器 :
如果我們使用ELC事件鏈接控制器來(lái)控制的話,我們就不能夠使能DAADSCR寄存器。 將DAADST位設(shè)置為0,允許DADRn寄存器值隨時(shí)轉(zhuǎn)換為模擬數(shù)據(jù)。 將DAADST位設(shè)置為1,允許D/A轉(zhuǎn)換與同步D/A轉(zhuǎn)換同步,使來(lái)自ADC12的輸入信號(hào)同步(單元1)。 使用此位直到DADC12(單元1)完成A/D轉(zhuǎn)換才開始D/A轉(zhuǎn)換,即使DADRn寄存器被改變。
DAADUSR寄存器 :
DAADUSR寄存器選擇ADC12單元一進(jìn)行D/A和A/D同步轉(zhuǎn)換。 將AMADSEL1位設(shè)置為1,選擇ADC單元1作為DAC的同步單元。 將AMADSEL1位設(shè)置為0,不選擇ADC單元同步單元。
26.3. 生成正弦波數(shù)據(jù)表
要輸出正弦波,實(shí)質(zhì)是要控制DAC以v=sin(t)的正弦函數(shù)關(guān)系輸出電壓,其中v為電壓輸出,t為時(shí)間。
而由于模擬信號(hào)連續(xù)而數(shù)字信號(hào)是離散的,所以使用DAC產(chǎn)生正弦波時(shí),只能按一定時(shí)間間隔輸出正弦曲線上的點(diǎn),在該時(shí)間段內(nèi)輸出相同 的電壓值,若縮短時(shí)間間隔,提高單個(gè)周期內(nèi)的輸出點(diǎn)數(shù),可以得到逼近連續(xù)正弦波的圖形,見 圖26_3,若在外部電路加上適當(dāng)?shù)?a href="http://m.1cnz.cn/tags/電容濾波/" target="_blank">電容濾波,可得到更完美的圖形。
圖 26?3 DAC按點(diǎn)輸出正弦波數(shù)據(jù)(左:32個(gè)點(diǎn),右:128個(gè)點(diǎn))
由于正弦曲線是周期函數(shù),所以只需要得到單個(gè)周期內(nèi)的數(shù)據(jù)后按周期重復(fù)即可,而單個(gè)周期內(nèi)取樣輸出的點(diǎn)數(shù)又是有限的,所以為了得到呈v=sin(t)函數(shù)關(guān)系電壓值的數(shù)據(jù)通常不會(huì)實(shí)時(shí)計(jì)算獲取,而是預(yù)先計(jì)算好函數(shù)單個(gè)周期內(nèi)的電壓數(shù)據(jù)表,并且轉(zhuǎn)化成以DAC寄存器表示的值。
如sin函數(shù)值的范圍為[-1: +1],而RA6M5的DAC輸出電壓范圍為[0~3.3]V,按12位DAC分辨率表示的方法,可寫入寄存器的最大值為2^12^ = 4096,即范圍為[0:4096]。 所以,實(shí)際輸出時(shí),會(huì)進(jìn)行如下處理:
- 抬升sin函數(shù)的輸出為正值:v = sin(t)+1 ,此時(shí),v的輸出范圍為[0:2];
- 擴(kuò)展輸出至DAC的全電壓范圍: v = 3.3*(sin(t)+1)/2 ,此時(shí),v的輸出范圍為[0:3.3],正是DAC的電壓輸出范圍,擴(kuò)展至全電壓范圍可以充分利用DAC的分辨率;
- 把電壓值以DAC寄存器的形式表示:Reg_val = 2 ^12^ /3.3 * v = 2 ^11^ *(sin(t)+1),此時(shí),存儲(chǔ)到DAC寄存器的值范圍為[0:4095];
- 實(shí)踐證明,在sin(t)的單個(gè)周期內(nèi),取32個(gè)點(diǎn)進(jìn)行電壓輸出已經(jīng)能較好地還原正弦波形,所以在t∈[0:2π]區(qū)間內(nèi)等間距根據(jù)上述Reg_val公式運(yùn)算得到32個(gè)寄存器值,即可得到正弦波表;
- 控制DAC輸出時(shí),每隔一段相同的時(shí)間從上述正弦波表中取出一個(gè)新數(shù)據(jù)進(jìn)行輸出,即可輸出正弦波。 改變間隔時(shí)間的單位長(zhǎng)度,可以改變正弦波曲線的周期。
為方便起見,我們使用了Python和Matlab腳本制作正弦波表,腳本的代碼存儲(chǔ)在本工程的目錄下,感興趣可以打開文件查看,以下列出Python腳本代碼,見代碼清單 26?2。
代碼清單 26?2 制作正弦波數(shù)據(jù)表的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
外部庫(kù):matplotlib1.5.3、numpy1.11.2
運(yùn)行方式:
在命令行中輸入:python sinWave.py
運(yùn)行結(jié)果:
命令行中會(huì)打印計(jì)算得的各點(diǎn)數(shù)據(jù),
在當(dāng)前目錄下會(huì)生成py_dac_sinWav.c文件,包含上述數(shù)據(jù),
并且會(huì)彈出描繪曲線的對(duì)話框。
"""
import matplotlib.pyplot as plt
import numpy as np
import math
#修改本變量可以更改點(diǎn)數(shù),如16、32、64等
POINT_NUM = 32
pi = math.pi
#一個(gè)周期 POINT_NUM 個(gè)點(diǎn)
n = np.linspace(0,2*pi,POINT_NUM)
#計(jì)算POINT_NUM個(gè)點(diǎn)的正弦值
a = map(math.sin,n)
r =[]
for i in a:
#調(diào)整幅值至在0~1區(qū)間
i+=1
#按3.3V電壓調(diào)整幅值
i*= 3.3/2
#求取dac數(shù)值,12位dac LSB = 3.3V/2**12
ri = round(i*2**12/3.3)
#檢查參數(shù)
if ri >= 4095:
ri = 4095
#得到dac數(shù)值序列
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腳本的實(shí)現(xiàn)原理就是前面介紹的正弦波數(shù)據(jù)表的制作過(guò)程,運(yùn)行后,該腳本把得到的正弦波表數(shù)據(jù)輸出到目錄下的py_dac_sinWav.c文件中,見代碼清單 26?3,并且根據(jù)取樣點(diǎn)描繪出示意圖,見圖 26?4。 Matlab腳本原理相同,此處不再列出,實(shí)際上使用C語(yǔ)言也能制作正弦波表,只是畫圖不方便而已。
代碼清單 26?3 生成的正弦波數(shù)據(jù)表 [](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 腳本根據(jù)正弦波表描繪的曲線圖
26.4. DAC程序設(shè)計(jì)
26.4.1. 硬件設(shè)計(jì)
我們使用引出來(lái)的排針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. 軟件設(shè)計(jì)
26.4.2.1. 新建工程
e2 studio :新建一個(gè)的RA6M5工程, 然后將工程文件夾重命名為 “25_DAC” ,之后將其加入到我們的e2 studio工作空間中。
Keil :我們可以拷貝一份我們之前的Keil工程模板, 然后將工程文件夾重命名為 “25_DAC” ,并進(jìn)入該文件夾雙擊里面的 Keil 工程文件,打開該工程。
26.4.2.2. FSP配置
我們先打開e2 studio軟件里面的 Smart Configurator 配置FSP。 雙擊 configuration.xml 打開配置界面: 然后點(diǎn)開依次點(diǎn)擊 Stacks -> New Stack -> Analog -> DAC(r_dac) 來(lái)配置DAC模塊。
DAC頁(yè)面的屬性介紹
DAC 屬性介紹 [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter26/chapter26.html#id25 "永久鏈接至表格")| Name | 名稱 |
| - | - |
| ---------------------- |
渠道 | 通道 |
---|---|
與 ADC 同步 | 同步與ADC |
日期格式 | 數(shù)據(jù)格式 |
輸出放大器 | 使能DAC輸出放大器 |
內(nèi)部輸出 | 內(nèi)部輸出 |
ELC 觸發(fā)源 | ELC 觸發(fā) |
配置完成之后可以按下快捷鍵“Ctrl + S”保存, 最后點(diǎn)右上角的 “Generate Project Content” 按鈕,讓軟件自動(dòng)生成配置代碼即可。
26.4.2.3. DAC初始化
/**
* @brief 初始化DAC
* @param 無(wú)
* @retval 無(wú)
*/
void dac_Init()
{
R_DAC_Open(DAC.p_ctrl, DAC.p_cfg);
R_DAC_Start(DAC.p_ctrl);
}
- R_DAC_Open()配置單個(gè) DAC 通道,啟動(dòng)通道,并提供用于 DAC API 寫入和關(guān)閉函數(shù)的句柄。
- R_DAC_Start()啟動(dòng) D/A 轉(zhuǎn)換輸出。
26.4.2.4. DAC設(shè)置電壓
/**
* @brief 設(shè)置當(dāng)前的電壓3.3V
* @param 需要控制的電壓
* @retval 無(wú)
*/
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);
}
通過(guò)電壓轉(zhuǎn)換公式將輸入的模擬量轉(zhuǎn)換為數(shù)值量,輸入到R_DAC_Write()函數(shù)里, R_DAC_Write()會(huì)將數(shù)據(jù)寫入到 D/A 轉(zhuǎn)換器里。
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 輸入可以調(diào)節(jié)波形的寬度
* @retval 無(wú)
*/
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);
}
}
通過(guò)輪循的方式將之前python生成的正弦波數(shù)據(jù)輸入到R_DAC_Write()函數(shù)里面, 并且延時(shí)一段時(shí)間。 而延時(shí)時(shí)間就是我們輸入到函數(shù)里面的數(shù)值, 通過(guò)改變這一數(shù)值我們就可以調(diào)節(jié)正弦波的周期以及頻率。
26.4.2.6. 主函數(shù)
void hal_entry(void)
{
dac_Init(); //DAC初始化
while(1)
{
dac_Circle(100); //正弦波函數(shù)
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
26.4.3. 下載驗(yàn)證
用USB線連接開發(fā)板的“USB轉(zhuǎn)串口”接口跟電腦,把編譯好的程序下載到開發(fā)板,使用示波器測(cè)量P014的引腳可看到正弦波形(示波器使用x10倍檔測(cè)量更加準(zhǔn)確),見圖 26?6,注意觀察圖中示波器測(cè)量出的頻率值和電壓峰值。
圖 26?6 使用示波器測(cè)量出的電壓波形
評(píng)論
查看更多