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