開發(fā)環(huán)境:
MDK:Keil 5.30
開發(fā)板:GD32F207I-EVAL
MCU:GD32F207IK
1 DAC工作原理
1.1 DAC介紹
數(shù)字/模擬轉(zhuǎn)換模塊(DAC)是12位數(shù)字輸入,電壓輸出的數(shù)字/模擬轉(zhuǎn)換器。DAC可以配置為8位或12位模式,也可以與DMA控制器配合使用。DAC工作在12位模式時,數(shù)據(jù)可以設(shè)置成左對齊或右對齊。DAC模塊有2個輸出通道,每個通道都有單獨(dú)的轉(zhuǎn)換器。在雙DAC模式下,2個通道可以獨(dú)立地進(jìn)行轉(zhuǎn)換,也可以同時進(jìn)行轉(zhuǎn)換并同步地更新2個通道的輸出。DAC可以通過引腳輸入?yún)⒖茧妷?a href="http://www.1cnz.cn/v/tag/3668/" target="_blank">VREF+ 以獲得更精確的轉(zhuǎn)換結(jié)果。
1.2 DAC主要特征
● 2個DAC轉(zhuǎn)換器:每個轉(zhuǎn)換器對應(yīng)1個輸出通道
● 8位或者12位單調(diào)輸出
● 12位模式下數(shù)據(jù)左對齊或者右對齊
● 同步更新功能
● 噪聲波形生成或三角波形生成
● 雙DAC通道同時或者分別轉(zhuǎn)換
● 每個通道都有DMA功能
● 外部觸發(fā)轉(zhuǎn)換
● 輸入?yún)⒖茧妷篤REF+
【注意】一旦使能DACx通道,相應(yīng)的GPIO引腳(PA4或者PA5)就會自動與DAC的模擬輸出相連(DAC_OUTx)。為了避免寄生的干擾和額外的功耗,引腳PA4或者PA5在之前應(yīng)當(dāng)設(shè)置成模擬輸入(AIN)。
1.3 DAC功能描述
- 使能DAC通道
將DAC_CTL 寄存器中的 DENx 位置 ’1’ 即可打開對DAC通道x 的供電。經(jīng)過一段啟動時間tWAKEUP,DAC通道x 即被使能。
注意:DENx位只會使能DAC通道x的模擬部分,即便該位被置’0’,DAC通道x的數(shù)字部分仍然工作。
- __使能DAC輸出緩存 __
DAC集成了2個輸出緩存,可以用來減少輸出阻抗,無需外部運(yùn)放即可直接驅(qū)動外部負(fù)載。每個DAC通道輸出緩存可以通過設(shè)置 DAC_CTL 寄存器的 DBOFFx 位來開啟或者關(guān)閉緩沖區(qū)。
- __DAC輸出電壓 __
數(shù)字輸入經(jīng)過DAC被線性地轉(zhuǎn)換為模擬電壓輸出,其范圍為0到VREF+。任一DAC通道引腳上的輸出電壓滿足下面的關(guān)系:
DAC輸出 = VREF x (DAC_DO / 4096)
【注】官方手冊有問題的,這里應(yīng)該是4096
- DAC數(shù)據(jù)格式
根據(jù)選擇的配置模式,數(shù)據(jù)按照下文所述寫入指定的寄存器:
●8位數(shù)據(jù)右對齊:用戶須將數(shù)據(jù)寫入寄存器DACx_R8DH [7:0]位
●12位數(shù)據(jù)左對齊:用戶須將數(shù)據(jù)寫入寄存器DACx_L12DH[15:4]位
●12位數(shù)據(jù)右對齊:用戶須將數(shù)據(jù)寫入寄存器DACx_R12DH[11:0]位
經(jīng)過相應(yīng)的移位后,寫入的數(shù)據(jù)被轉(zhuǎn)存到DACx_DH寄存器中。隨后,DACx_DH寄存器的內(nèi)容或被自動地傳送到DACx_DO寄存器,或通過軟件觸發(fā)或外部事件觸發(fā)被傳送到DACx_DO寄存器。
- DAC轉(zhuǎn)換
如果使能了外部觸發(fā)(通過設(shè)置 DAC_CTL 寄存器的 DTENx 位),根據(jù)已經(jīng)選擇的觸發(fā)事件,DAC 保持?jǐn)?shù)據(jù)(DACx_DH)會被轉(zhuǎn)移到 DAC 數(shù)據(jù)輸出寄存器(DACx_DO)。否則,在外部觸發(fā)沒有使能的情況下, DAC 保持?jǐn)?shù)據(jù)(DACx_DH)會被自動轉(zhuǎn)移到 DAC 數(shù)據(jù)輸出寄存器(DACx_DO)。
當(dāng) DAC 保持?jǐn)?shù)據(jù)(DACx_DH)加載到 DACx_DO 寄存器時,經(jīng)過 tSETTLING 時間之后,模擬輸出變得有效, tSETTLING 的值與電源電壓和模擬輸出負(fù)載有關(guān)。
- 選擇DAC觸發(fā)
通過設(shè)置 DAC_CTL 寄存器中 DTENx 位來使能 DAC 外部觸發(fā)。觸發(fā)源可以通過 DAC_CTL寄存器中 DTSELx 位來進(jìn)行選擇。
TIMERx_TRGO 信號是由定時器生成的,而軟件觸發(fā)是通過設(shè)置 DAC_SWT 寄存器的 SWTRx位生成的。
2 DAC寄存器描述
我們介紹一下要實(shí)現(xiàn) DAC 輸出,需要用到的一些寄存器。首先是 DAC控制寄存器DAC_CTL,該寄存器的各位描述如下圖所示。
DAC_CTL的低 16 位用于控制通道0,而高 16 位用于控制通道 1,我們這里僅列出比較重要的最低 8 位的詳細(xì)描述。
首先,我們來看 DAC 通道0使能位(DEN0),該位用來控制 DAC 通道 0使能的,本章我們就是用的 DAC 通道 0,所以該位設(shè)置為 1。
再看關(guān)閉 DAC 通道 0輸出緩存控制位(DBOFF0),這里 GD32 的 DAC 輸出緩存做的有些不好,如果使能的話,雖然輸出能力強(qiáng)一點(diǎn),但是輸出沒法到 0,這是個很嚴(yán)重的問題。所以本章我們不使用輸出緩存。即設(shè)置該位為 1。DAC 通道0觸發(fā)使能位(DTEN0),該位用來控制是否使用觸發(fā),里我們不使用觸發(fā),所以設(shè)置該位為 0。DAC 通道 0觸發(fā)選擇位(DTSEL0 [2:0]),這里我們沒用到外部觸發(fā),所以設(shè)置這幾個位為 0就行了。DAC 通道 0噪聲/三角波生成使能位(DWM0 [1:0]),這里我們同樣沒用到波形發(fā)生器,故也設(shè)置為 0 即可。DAC 通道0噪聲波位寬(DWBW0 [3:0]),這些位僅在使用了波形發(fā)生器的時候有用,本章沒有用到波形發(fā)生器,故設(shè)置為 0 就可以了。
最后是 DAC 通道0 DMA 使能位(DDMAEN0)。
在 DAC_CTL設(shè)置好之后, DAC 就可以正常工作了, 我們僅需要再設(shè)置 DAC 的數(shù)據(jù)保持寄存器的值,就可以在 DAC 輸出通道得到你想要的電壓了(對應(yīng) IO 口設(shè)置為模擬輸入)。假設(shè)我們用的是 DAC 通道 0的 12 位右對齊數(shù)據(jù)保持寄存器:DAC0_R12DH,該寄存器各位描述如下圖所示。
該寄存器用來設(shè)置 DAC 輸出,通過寫入 12 位數(shù)據(jù)到該寄存器,就可以在 DAC 輸出通道0得到我們所要的結(jié)果。
3 DAC應(yīng)用代碼實(shí)現(xiàn)
3.1 DAC普通方式輸出
本章我們將使用庫函數(shù)的方法來設(shè)置 DAC 模塊的通道0來輸出模擬電壓,其詳細(xì)設(shè)置步驟如下:
1)開啟 PA 口時鐘,設(shè)置 PA4為模擬輸入。
GD32F207的 DAC 通道0在 PA4上,所以,我們先要使能PA4的時鐘, 然后設(shè)置 PA4為模擬輸入。 DAC 本身是輸出,但是為什么端口要設(shè)置為模擬輸入模式呢?因為一但使能 DACx 通道后,相應(yīng)的 GPIO 引腳(PA4 或者 PA5)會自動與 DAC 的模擬輸出相連,設(shè)置為輸入,是為了避免額外的干擾 。
使能 GPIOA 時鐘:
rcu_periph_clock_enable(RCU_GPIOA);
設(shè)置 PA5為模擬輸入只需要設(shè)置初始化參數(shù)即可:
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
2)使能 DAC時鐘。
同其他外設(shè)一樣,要想使用,必須先開啟相應(yīng)的時鐘。DAC 模塊時鐘是由 APB1提供的。
rcu_periph_clock_enable(RCU_DAC); //使能 DAC 通道時鐘
3)初始化 DAC,設(shè)置 DAC 的工作模式。
該部分設(shè)置全部通過 DAC_CR 設(shè)置實(shí)現(xiàn),包括:DAC 通道 使能、 DAC 通道輸出緩存關(guān)閉、不使用觸發(fā)、不使用波形發(fā)生器等設(shè)置。
/* configure the DAC0 */
dac_trigger_disable(DAC0);
dac_wave_mode_config(DAC0, DAC_WAVE_DISABLE);
dac_output_buffer_enable(DAC0);
dac_trigger_disable()函數(shù)用來關(guān)閉觸發(fā)功能。
dac_wave_mode_config()設(shè)置是否使用波形發(fā)生,這里我們前面同樣講解過不使用。所以值為 DAC_WAVE_DISABLE。
dac_output_buffer_enable用于緩存的配置,如果不使用輸出緩存,因此使用dac_output_buffer_enable()關(guān)閉緩存。
4)使能 DAC 轉(zhuǎn)換通道
初始化 DAC 之后,理所當(dāng)然要使能 DAC 轉(zhuǎn)換通道,庫函數(shù)方法是:
dac_enable(DAC0); //使能 DAC0
5)設(shè)置 DAC 的輸出值。
通過前面 4 個步驟的設(shè)置, DAC 就可以開始工作了,我們使用 12 位右對齊數(shù)據(jù)格式,所以我們通過設(shè)置 DAC0_R12DH,就可以在 DAC 輸出引腳(PA4)得到不同的電壓值了。 庫函數(shù)的函數(shù)是:
dac_data_set(DAC0, DAC_ALIGN_12B_R, 0);
第二個參數(shù)設(shè)置對齊方式,可以為 12 位右對齊DAC_ALIGN_12B_R, 12 位左對齊DAC_ALIGN_12B_L 以及 8 位右對齊 DAC_ALIGN_8B_R方式。
第三個參數(shù)就是 DAC 的輸入值了,這個很好理解,初始化設(shè)置為 0。這里,還可以讀出 DAC 的數(shù)值,函數(shù)是:
dac_output_value_get (DAC0);
因此DAC0的整體配置如下:
/*
brief Configure the DAC peripheral
param[in] none
param[out] none
retval none
*/
void dac_config(void)
{
/* DAC GPIO configuration */
dac_gpio_config();
/* enable the clock of DAC */
rcu_periph_clock_enable(RCU_DAC);
/* configure the DAC0 */
dac_trigger_disable(DAC0);
dac_wave_mode_config(DAC0, DAC_WAVE_DISABLE);
dac_output_buffer_enable(DAC0);
/* enable DAC0 and set data */
dac_enable(DAC0);
}
主函數(shù)如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
uint8_t i=0;
uint16_t da=0;
//systick init
sysTick_init();
//usart init 115200 8-N-1
com_init(COM1);
/*DAC初始化*/
dac_config();//調(diào)用DAC配置
while(1)
{
da=0;
for(i=0;i<=10;i++)
{
da=i*400;
dac_data_set(DAC0, DAC_ALIGN_12B_R, da);
printf("da=%f v\\r\\n",3.3*((float)da/4096));
//printf("%3.2f\\r\\n",3.3*((float)da/4096));
delay_ms(1000);
}
}
}
這代碼很簡單,首先是對串口等進(jìn)行初始化,接下來就是循環(huán)設(shè)置電壓并輸出。
如果想要使用軟件觸發(fā),則需要將DAC配置為DAC_TRIGGER_SOFTWARE。
dac_trigger_source_config(DAC0, DAC_TRIGGER_SOFTWARE);
dac_trigger_enable(DAC0);
然后在主函數(shù)中需要進(jìn)行軟件觸發(fā)。
dac_software_trigger_enable(DAC0);
3.2 DAC正弦波輸出實(shí)現(xiàn)
本章我們還要通過DAC實(shí)現(xiàn)正弦波輸出,那么就需要找到正弦波的曲線散點(diǎn),其計算方式如下所示:
原系統(tǒng)時鐘周期:T_Systick=1/120M(單位:秒)
因為定時時鐘預(yù)分頻:Prescaler=0
所以定時時鐘周期:T_TIMER=T_Systick*(Prescaler+1)=1/120M(單位:秒)
因為設(shè)置的定時更新周期:Period=19
所以定時器更新周期:T_update=T_TIMER*(Period+1)=20/120M
而DAC數(shù)據(jù)更新率等于定時器更新速率:即DAC的數(shù)據(jù)更新周期為:
DAC_update=T_update=20/120M
本實(shí)驗有32個數(shù)據(jù)點(diǎn),則正弦波的周期為:
T_sin=DAC_update*點(diǎn)數(shù)=640/120M
最后求的正弦波的頻率為:
f_sin=1/T_sin=187500Hz
因此正弦波的頻率為:
f_sin=1/T_Systick/(Prescaler+1)/(Period+1)/點(diǎn)數(shù)
其波形數(shù)據(jù)如下:
const uint16_t Sine12bit[32] = {
2448,2832,3186,3496,3751,3940,4057,4095,4057,3940,
3751,3496,3186,2832,2448,2048,1648,1264,910,600,345,
156,39,0,39,156,345,600,910,1264,1648,2048
};
接下來看看主函數(shù)。
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//systick init
sysTick_init();
//usart init 115200 8-N-1
com_init(COM1);
/*DAC初始化*/
dac_mode_init();
while(1)
{
delay_ms(1000);
}
}
主函數(shù)很簡單,那我們進(jìn)入DAC_Mode_Init()看看吧。
/*
brief Configure the DAC mode
param[in] none
param[out] none
retval none
*/
void dac_mode_init(void)
{
// dac 配置
dac_config();
//DMA配置
dma_config();
// TIMER配置并啟動
timer_config();
}
dac_mode_init()函數(shù)初始化了DAC、DMA和TIMER,啟動定時器,利用定時器的觸發(fā)DAC數(shù)據(jù)更新。
完整配置代碼如下:
/*
brief Configure the GPIO peripheral
param[in] none
param[out] none
retval none
*/
static void dac_gpio_config(void)
{
/* enable the clock of GPIO */
rcu_periph_clock_enable(RCU_GPIOA);
/* config the GPIO as analog mode */
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
}
/*
brief Configure the DAC peripheral
param[in] none
param[out] none
retval none
*/
static void dac_config(void)
{
/* DAC GPIO configuration */
dac_gpio_config();
/* enable the clock of DAC */
rcu_periph_clock_enable(RCU_DAC);
dac_wave_mode_config(DAC0, DAC_WAVE_DISABLE);
dac_output_buffer_disable(DAC0);
/* configure the DAC0 */
dac_trigger_source_config(DAC0, DAC_TRIGGER_T1_TRGO);
/* DAC的DMA功能使能 */
dac_dma_enable(DAC0);
dac_trigger_enable(DAC0);
/* enable DAC0 and set data */
dac_enable(DAC0);
}
/*
brief configure the DMA peripheral
param[in] none
param[out] none
retval none
*/
static void dma_config(void)
{
dma_parameter_struct dma_init_struct;
/* enable DMA CLK */
rcu_periph_clock_enable(RCU_DMA1);
/* deinitialize DMA1 channel2 */
dma_deinit(DMA1, DMA_CH2);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;/* 存儲器到外設(shè)方向 */
dma_init_struct.memory_addr = (uint32_t)Sine12bit; /* 存儲器基地址 */
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
//dma_init_struct.periph_addr = ((uint32_t)(DAC0_R12DH_ADDRESS)); /* 外設(shè)基地址 */
dma_init_struct.periph_addr = ((uint32_t)(&DAC0_R12DH));
dma_init_struct.number = 32; /* 傳輸數(shù)據(jù)個數(shù) */
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA1, DMA_CH2, &dma_init_struct);
/* configure DMA mode 存儲器到存儲器DMA傳輸禁能*/
dma_memory_to_memory_disable(DMA1, DMA_CH2);
//DMA循環(huán)模式開啟
dma_circulation_enable(DMA1, DMA_CH2);
dma_channel_enable(DMA1, DMA_CH2);
}
/*
brief configure the TIMER peripheral
param[in] none
param[out] none
retval none
*/
static void timer_config(void)
{
timer_parameter_struct timer_initpara;
//Enable TIMER clock
rcu_periph_clock_enable(RCU_TIMER1);
timer_deinit(TIMER1);
/* TIMER configuration */
timer_initpara.prescaler = 0;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 19;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER1, &timer_initpara);
//定時器主輸出觸發(fā)源選擇
timer_master_output_trigger_source_select(TIMER1,TIMER_TRI_OUT_SRC_UPDATE);
//定時器更新事件使能
timer_update_event_enable(TIMER1);
/* TIMER enable */
timer_enable(TIMER1);
}
當(dāng)然也可使用TIMER中斷來更新數(shù)據(jù),從而也可實(shí)現(xiàn)正弦波,但是會消耗CPU資源,建議使用筆者給出的方式。
4 實(shí)驗現(xiàn)象
4.1 DAC普通方式輸出
將程序編譯好后下載到板子中,通過串口助手可以看到在接收區(qū)有電壓值輸出。這個和ADC輸入不同,我們使用DAC的目的是通過板子得到相應(yīng)的模擬電壓值,看到串口的輸出值只是我們的調(diào)試手段,要想確認(rèn)實(shí)驗是否成功,是需要通過電壓表測量PA4的電壓值是否串口的輸出一致。我們設(shè)置的步進(jìn)是400,因此電壓值也是在以400*3.3/4096的電壓步進(jìn)。
當(dāng)然啦,還需要萬用表測量引腳電壓即可。你可以使用一個固定值,或者延時更長這樣便于測量。為了更好的測量,筆者將轉(zhuǎn)換電壓設(shè)置為固定值,因此在循環(huán)體的前面加了一句話。
da = 2048;
接下來看看實(shí)驗結(jié)果:
當(dāng)然也可以使用萬用表測量實(shí)際電壓。
4.2 DAC正弦波輸出
將程序編譯好后下載到板子中,通過示波器可看到波形輸出。
這里測量出的正弦波的頻率是187.42kHz,和計算結(jié)果相符。
-
mcu
+關(guān)注
關(guān)注
146文章
17123瀏覽量
350983 -
dac
+關(guān)注
關(guān)注
43文章
2291瀏覽量
190975 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5032瀏覽量
97371 -
模擬轉(zhuǎn)換器
+關(guān)注
關(guān)注
0文章
42瀏覽量
12690 -
GD32
+關(guān)注
關(guān)注
7文章
403瀏覽量
24328
發(fā)布評論請先 登錄
相關(guān)推薦
評論