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。
- 第一步在DADPR寄存器中設置我們想要轉換的數據格式
- 觸發使能寄存器,使得DAC使能寄存器DACR.DAOEn(n=0,1),以開始數模轉換轉換的結果將在一段時間t過后從輸出引腳DA0上輸出。 如果使能寄存器一直為1的話,DAC將一直轉換輸出,直到將DAC使能寄存器DACR.DAOEn(n=0,1)位設置0。
- 若在轉換的過程中,想要改變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]。 所以,實際輸出時,會進行如下處理:
- 抬升sin函數的輸出為正值: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)的單個周期內,取32個點進行電壓輸出已經能較好地還原正弦波形,所以在t∈[0:2π]區間內等間距根據上述Reg_val公式運算得到32個寄存器值,即可得到正弦波表;
- 控制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);
}
- R_DAC_Open()配置單個 DAC 通道,啟動通道,并提供用于 DAC API 寫入和關閉函數的句柄。
- 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

























評論