GD32F307 DAC 输出波形
文章目錄
- DAC
- DAC_CTL 控制寄存器
 
- 定時器
- TIMERx_CTL1 控制寄存器
- 改變波形頻率
 
- DMA
- DMA和外設(shè)配合
- DMA_CHxCNT計數(shù)寄存器
 
- 波形曲線
- 總結(jié)
- 源碼
 
DAC
如下面框圖所示,使能外部觸發(fā)后(通過設(shè)置 DAC_CTL 寄存器的 DTENx 位), 當(dāng)已經(jīng)選擇的觸發(fā)事件發(fā)
 生, DAC 保持?jǐn)?shù)據(jù)(DACx_DH)會被轉(zhuǎn)移到 DAC 數(shù)據(jù)輸出寄存器(DACx_DO),經(jīng)過一段時間之后,模擬輸出變得有效。DAC引腳上的模擬輸出電壓DACoutput=VREF×DAC_DO/4096。
對于12位的DAC保持?jǐn)?shù)據(jù)(DACx_DH),可以通過對DACx_R12DH、DACx_L12DH和DACx_R8DH中的任意一個寄存器寫入數(shù)據(jù)來配置。
在外部觸發(fā)使能的情況下,通過設(shè)置DAC_CTL寄存器的DDMAENx位來使能DMA請求。當(dāng)有外部硬件觸發(fā)的時候(不是軟件觸發(fā)),則產(chǎn)生一個DMA請求。
DAC_CTL 控制寄存器
| DWBW0[3:0] | DAC0 噪聲波位寬 | 
| DDMAEN0 | DAC0 DMA 使能 | 
| DWM0[1:0] | DAC0 噪聲波模式 | 
| DTSEL0[2:0] | DAC0 觸發(fā)選擇 | 
| DBOFF0 | DAC0 輸出緩沖區(qū) | 
| DEN0 | DAC0 使能 | 
| DTEN0 | DAC0 觸發(fā)使能 | 
配置DAC其實還是配置的上面這些東西,只不過,代碼里面是調(diào)用了固件庫函數(shù)來配的。
其中在DAC0外部觸發(fā)使能(DTEN0=1)的情況下,DAC0外部觸發(fā)源選擇TIMER6 TRGO。
/*DAC通道輸出配置,定時器6觸發(fā),不開啟輸出緩存*/ static void sin_adc_channel_config(void) {//DAC外設(shè)復(fù)位dac_deinit();/* DAC觸發(fā)禁能 */dac_trigger_disable(SIN_DAC);//DAC噪聲波模式選擇dac_wave_mode_config(SIN_DAC, DAC_WAVE_DISABLE);//DAC輸出緩沖區(qū)禁能dac_output_buffer_disable(SIN_DAC);/* DAC觸發(fā)源的選擇*/dac_trigger_source_config(SIN_DAC,DAC_TRIGGER_T6_TRGO);/* DAC的DMA功能使能 */dac_dma_enable(SIN_DAC);/* DAC觸發(fā)使能 */dac_trigger_enable(SIN_DAC);/* DAC使能 */dac_enable(SIN_DAC); }定時器
選用基本定時器TIM6觸發(fā)DAC。
如下面框圖所示,TIMER_CK驅(qū)動計數(shù)器預(yù)分頻器,預(yù)分頻值由TIMERx_PSC寄存器確定,TIMER_CK經(jīng)過預(yù)分頻器產(chǎn)生PSC_CLK。向上計數(shù)模式下,計數(shù)器從0開始向上連續(xù)計數(shù)到自動加載值(在TIMERx_CAR寄存器中),然后,重新從0開始向上計數(shù)并產(chǎn)生上溢事件。此時,如果TIMERx_SWEVG寄存器的UPG位置1,計數(shù)值會被清0,并產(chǎn)生更新事件。發(fā)生更新事件時,所有的寄存器(重復(fù)計數(shù)器,自動重載寄存器,預(yù)分頻寄存器)都將被更新。
TIMERx_CTL1 控制寄存器
其中MMC[2:0]位控制TRGO信號的選擇,使用timer_master_output_trigger_source_select函數(shù),主模式控制器選擇更新事件作為TRGO。
使用timer_update_event_enable函數(shù),將TIMERx_SWEVG寄存器的UPG位置1,那么定時器產(chǎn)生上溢事件時會產(chǎn)生更新事件,然后觸發(fā)TIMERx_TRGO。進而觸發(fā)DAC。
//定時器主輸出觸發(fā)源選擇timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定時器更新事件使能timer_update_event_enable(SIN_TIM);改變波形頻率
這里面,設(shè)置不同的定時周期,會改變輸出波形的頻率。
 按照下面這樣設(shè)置,最終會得到4KHZ的正弦波。
DMA
DMA控制器提供了一種硬件的方式,在外設(shè)和存儲器之間或者存儲器和存儲器之間傳輸數(shù)據(jù)。無需CPU的介入,使CPU可以專注在處理其他系統(tǒng)功能上。
DMA傳輸 ,從源地址讀取數(shù)據(jù)后,將讀取的數(shù)據(jù)存儲到目的地址。
AHB從接口配置DMA,AHB主接口進行數(shù)據(jù)傳輸,仲裁器進行DMA請求的優(yōu)先級管理。
dma_parameter_struct結(jié)構(gòu)體:
| periph_addr | 外設(shè)基地址 | 
| periph_width | 外設(shè)數(shù)據(jù)傳輸寬度 | 
| memory_addr | 存儲器基地址 | 
| memory_width | 存儲器數(shù)據(jù)傳輸寬度 | 
| number | DMA通道數(shù)據(jù)傳輸數(shù)量 | 
| priority | DMA通道傳輸軟件優(yōu)先級 | 
| periph_inc | 外設(shè)地址生成算法模式 | 
| memory_inc | 存儲器地址生成算法模式 | 
| direction | DMA通道數(shù)據(jù)傳輸方向 | 
初始化,設(shè)定上面結(jié)構(gòu)體的值,其實還是對DMA_CHxCTL寄存器的一些設(shè)置。設(shè)置傳輸方向為從存儲器讀出并寫入外設(shè)。
存儲器和外設(shè)都獨立的支持兩種地址生成算法:固定模式和增量模式。寄存器DMA_CHxCTL的PNAGA和MNAGA位用來設(shè)置存儲器和外設(shè)的地址生成算法,固定模式中,地址一直固定為初始化的基地址,增量模式中,下一次傳輸數(shù)據(jù)的地址是當(dāng)前地址加1(或2、4,取決于數(shù)據(jù)傳輸寬度) ,前面波形數(shù)組uint16_t Sine[POINT_NUM2]定義的是U16,所以設(shè)置的寬度也是16bit。
//DMA配置 static void sin_dma_config(void) {dma_parameter_struct dma_init_struct;/* enable DMA CLK */rcu_periph_clock_enable(SIN_DMA_CLK);/* deinitialize DMA channel3(USART0 tx) */dma_deinit(SIN_DMA, SIN_DMA_CHANNEL);dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; // dma_init_struct.memory_addr = ;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT; // dma_init_struct.number = ; // dma_init_struct.periph_addr = ;dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;dma_init(SIN_DMA, SIN_DMA_CHANNEL, &dma_init_struct);/* configure DMA mode 存儲器到存儲器DMA傳輸禁能*/dma_memory_to_memory_disable(SIN_DMA, SIN_DMA_CHANNEL); }DMA和外設(shè)配合
循環(huán)模式用來處理連續(xù)的外設(shè)請求,循環(huán)模式中,當(dāng)每次DMA傳輸完成后,CNT值會被重新載入,且傳輸完成標(biāo)志位會被置1。
 DMA會一直響應(yīng)外設(shè)的請求,直到通道使能位(DMA_CHxCTL寄存器的CHEN位)被清0。
當(dāng)DMA控制器在同一時間接收到多個外設(shè)請求時,仲裁器將根據(jù)外設(shè)請求的優(yōu)先級來決定響應(yīng)哪一個外設(shè)請求。當(dāng)通道具有相同的軟件優(yōu)先級時,編號低的通道優(yōu)先級高。
多個外設(shè)請求被映射到同一個DMA 通道。這些請求信號在經(jīng)過邏輯或后進入DMA。通過配置對應(yīng)外設(shè)的寄存器,每個外設(shè)
 的請求均可以獨立的開啟或關(guān)閉。DMA1各通道請求表如下,由于外設(shè)是DAC_CH0,所以選用DMA1的Channel2通道。
為了保證數(shù)據(jù)的有效傳輸, DMA控制器中引入了外設(shè)和存儲器的握手機制。請求信號由外設(shè)發(fā)出,表明外設(shè)已經(jīng)準(zhǔn)備好發(fā)送或接收數(shù)據(jù),應(yīng)答信號由DMA控制器響應(yīng),表明DMA控制器已經(jīng)發(fā)送AHB命令去訪問外設(shè)。
DMA_CHxCNT計數(shù)寄存器
CNT[15:0],該寄存器表明還有多少數(shù)據(jù)等待被傳輸。一旦通道使能,該寄存器為只讀的,并在每個DMA傳輸之后值減1。如果該寄存器的值為0,無論通道開啟與否,都不會有數(shù)據(jù)傳輸。如果該通道工作在循環(huán)模式下,一旦通道的傳輸任務(wù)完成,該寄存器會被自動重裝載為初始設(shè)置值。程序中,用dma_transfer_number_config函數(shù)配置該寄存器的值。
#define ARRAYNUM(arr_name) (uint32_t)(sizeof(arr_name)/sizeof(*(arr_name))) #define DAC0_R12DH_ADDRESS ((uint32_t)0x40007408) void sin_dma_function_config(void) { //DMAx的通道y的存儲器基地址配置dma_memory_address_config(SIN_DMA,SIN_DMA_CHANNEL,(uint32_t)Sine);//配置DMAx通道y還有多少數(shù)據(jù)要傳輸dma_transfer_number_config(SIN_DMA,SIN_DMA_CHANNEL,ARRAYNUM(Sine));//DMAx的通道y的外設(shè)基地址配置dma_periph_address_config(SIN_DMA,SIN_DMA_CHANNEL,DAC0_R12DH_ADDRESS);//DMA循環(huán)模式開啟dma_circulation_enable(SIN_DMA, SIN_DMA_CHANNEL);//DMA的通道使能dma_channel_enable(SIN_DMA, SIN_DMA_CHANNEL); }外設(shè)基地址配置:
DAC0_R12DH地址偏移: 0x08
DAC 基地址: 0x4000 7400
DAC0_R12DH地址:0x4000 7408
波形曲線
其中可以修改點數(shù),使波形變得平滑;也可以修改波形幅值;也可以修改波形形狀。
#! python3 #coding=utf-8import matplotlib.pyplot as plt import numpy as np import math#修改本變量可以更改點數(shù),如16、32、64等 POINT_NUM = 120pi = 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()如果得到的值為a,那么(a/4096)*3.3就是實際輸出的電壓值。
uint16_t Sine[POINT_NUM2] = { 1241, 1307, 1372, 1437, 1501, 1565, 1628, 1690, 1750, 1809, 1867, 1922, 1976, 2028, 2077, 2125, 2169, 2212, 2251, 2288, 2322, 2352, 2380, 2404, 2426, 2444, 2458, 2469, 2477, 2481, 2482, 2480, 2474, 2464, 2451, 2435, 2415, 2393, 2367, 2337, 2305, 2270, 2232, 2191, 2147, 2101, 2053, 2002, 1949, 1895, 1838, 1780, 1720, 1659, 1597, 1533, 1469, 1405, 1339, 1274, 1208, 1143, 1078, 1013, 949, 886, 824, 762, 703, 644, 588, 533, 480, 430, 381, 335, 292, 251, 213, 177, 145, 116, 90, 67, 47, 31, 18, 9, 3, 0, 1, 5, 13, 24, 39, 57, 78, 102, 130, 161, 195, 231, 271, 313, 358, 405, 455, 506, 560, 616, 673, 732, 793, 855, 917, 981, 1045, 1110, 1176, 1241 };效果如下。
總結(jié)
1.使能TIM6觸發(fā)DAC,其中,將TIMERx_SWEVG寄存器的UPG位置1,定時器產(chǎn)生上溢事件時會產(chǎn)生更新事件,主模式控制器選擇更新事件作為TRGO。由于設(shè)置了DAC的DAC_CTL寄存器的DDMAENx位來使能DMA請求,當(dāng)有外部硬件觸發(fā)的時候,DAC則產(chǎn)生一個DMA請求。
3.使用DMA傳輸數(shù)據(jù),從存儲器讀出數(shù)據(jù)并寫入外設(shè),也就是說,DMA從Sine數(shù)組的地址讀數(shù)據(jù),寫到DAC0_R12DH寄存器里面。
2.觸發(fā)事件發(fā)生, DAC保持?jǐn)?shù)據(jù)(DACx_DH)會被轉(zhuǎn)移到DAC數(shù)據(jù)輸出寄存器(DACx_DO),經(jīng)過一段時間之后,DAC引腳上的輸出電壓DACoutput=VREF×DAC_DO/4096。
4.總而言之,定時器從0開始向上連續(xù)計數(shù)到自動加載值,然后,重新從0開始向上計數(shù)并產(chǎn)生上溢事件,TIMERx_SWEVG寄存器的UPG位置1,計數(shù)值會被清0,并產(chǎn)生更新事件,主模式控制器選擇更新事件作為TRGO,觸發(fā)DAC,產(chǎn)生DMA請求,搬運數(shù)組的數(shù)據(jù)。由于DMA設(shè)置為循環(huán)模式,當(dāng)每次DMA傳輸完成后,CNT值(待傳輸?shù)臄?shù)據(jù)個數(shù))會被重新載入,DMA會一直響應(yīng)外設(shè)的請求,如此循環(huán)往復(fù),把波形曲線的值寫到DAC0_R12DH寄存器里面,然后在DAC引腳上輸出電壓,DACoutput=VREF×DAC_DO/4096。
5.使用一個外設(shè),看用戶手冊,可以知道外設(shè)大概都有哪些功能,要使用外設(shè)的某些功能都需要怎么配置寄存器。寫程序的話,可能提供庫函數(shù),庫函數(shù)就是把配置寄存器的那些代碼給封裝起來了,然后使用庫函數(shù)把外設(shè)用起來就好了。
源碼
 GD32F307DAC輸出波形-單片機文檔類資源-CSDN文庫
 bsp_dac.c文件如下
main.c調(diào)用void sin_app(void)函數(shù)即可。
#include "systick.h" #include "bsp_dac.h" #define POINT_NUM 32 #define POINT_NUM2 120#define ARRAYNUM(arr_name) (uint32_t)(sizeof(arr_name)/sizeof(*(arr_name))) #define DAC0_R12DH_ADDRESS ((uint32_t)0x40007408)#define DAC_OUT_VAL (0x09B3)#define SIN_TIM TIMER6 #define SIN_TIM_CLK RCU_TIMER6#define SIN_DAC DAC0 #define SIN_DAC_CLK RCU_DAC#define SIN_PIN GPIO_PIN_4 #define SIN_GPIO_PORT GPIOA #define SIN_GPIO_CLK RCU_GPIOA#define SIN_DMA DMA1 #define SIN_DMA_CLK RCU_DMA1 #define SIN_DMA_CHANNEL DMA_CH2uint16_t Sine12bit[POINT_NUM] = {1241, 1491, 1731, 1950, 2141, 2295, 2405, 2468, 2481, 2443, 2356, 2223, 2050, 1844, 1613, 1367, 1116, 870, 639, 433, 260, 127, 40, 2, 14, 77, 188, 342, 532, 752, 991, 1241 }; uint16_t Sine[POINT_NUM2] = { 1241, 1307, 1372, 1437, 1501, 1565, 1628, 1690, 1750, 1809, 1867, 1922, 1976, 2028, 2077, 2125, 2169, 2212, 2251, 2288, 2322, 2352, 2380, 2404, 2426, 2444, 2458, 2469, 2477, 2481, 2482, 2480, 2474, 2464, 2451, 2435, 2415, 2393, 2367, 2337, 2305, 2270, 2232, 2191, 2147, 2101, 2053, 2002, 1949, 1895, 1838, 1780, 1720, 1659, 1597, 1533, 1469, 1405, 1339, 1274, 1208, 1143, 1078, 1013, 949, 886, 824, 762, 703, 644, 588, 533, 480, 430, 381, 335, 292, 251, 213, 177, 145, 116, 90, 67, 47, 31, 18, 9, 3, 0, 1, 5, 13, 24, 39, 57, 78, 102, 130, 161, 195, 231, 271, 313, 358, 405, 455, 506, 560, 616, 673, 732, 793, 855, 917, 981, 1045, 1110, 1176, 1241 };/*DAC引腳配置*/ static void sin_dac_gpio_config(void) {/* enable the clock of peripherals */rcu_periph_clock_enable(SIN_GPIO_CLK);rcu_periph_clock_enable(SIN_DAC_CLK);rcu_periph_clock_enable(RCU_AF);/* once enabled the DAC, the corresponding GPIO pin is connected to the DAC converter automatically */gpio_init(SIN_GPIO_PORT, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, SIN_PIN);}/*DAC通道輸出配置,定時器6觸發(fā),不開啟輸出緩存*/ static void sin_adc_channel_config(void) {dac_deinit();/* configure the DAC0 */dac_trigger_disable(SIN_DAC);dac_wave_mode_config(SIN_DAC, DAC_WAVE_DISABLE);dac_output_buffer_disable(SIN_DAC);/* DAC觸發(fā)源的選擇*/dac_trigger_source_config(SIN_DAC,DAC_TRIGGER_T6_TRGO);/* DAC的DMA功能使能 */dac_dma_enable(SIN_DAC);/* DAC觸發(fā)使能 */dac_trigger_enable(SIN_DAC);/* enable DAC0 */dac_enable(SIN_DAC);} //DMA配置 static void sin_dma_config(void) {dma_parameter_struct dma_init_struct;/* enable DMA CLK */rcu_periph_clock_enable(SIN_DMA_CLK);/* deinitialize DMA channel3(USART0 tx) */dma_deinit(SIN_DMA, SIN_DMA_CHANNEL);dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; // dma_init_struct.memory_addr = ;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT; // dma_init_struct.number = ; // dma_init_struct.periph_addr = ;dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;dma_init(SIN_DMA, SIN_DMA_CHANNEL, &dma_init_struct);/* configure DMA mode */dma_memory_to_memory_disable(SIN_DMA, SIN_DMA_CHANNEL); }void sin_config(void) {//引腳配置sin_dac_gpio_config();//通道配置sin_adc_channel_config();//DMA配置sin_dma_config(); }void sin_dma_function_config(void) { //DMAx的通道y的存儲器基地址配置dma_memory_address_config(SIN_DMA,SIN_DMA_CHANNEL,(uint32_t)Sine);//配置DMAx通道y還有多少數(shù)據(jù)要傳輸dma_transfer_number_config(SIN_DMA,SIN_DMA_CHANNEL,ARRAYNUM(Sine));//DMAx的通道y的外設(shè)基地址配置dma_periph_address_config(SIN_DMA,SIN_DMA_CHANNEL,DAC0_R12DH_ADDRESS);//DMA循環(huán)模式開啟dma_circulation_enable(SIN_DMA, SIN_DMA_CHANNEL);//DMA的通道使能dma_channel_enable(SIN_DMA, SIN_DMA_CHANNEL); }/*TIMx觸發(fā)配置*/ void sin_timx_trigger_function_config(void) {timer_parameter_struct timer_initpara;rcu_periph_clock_enable(SIN_TIM_CLK);timer_deinit(SIN_TIM);/* TIMER6 configuration */timer_initpara.prescaler = 1-1;//預(yù)分頻timer_initpara.counterdirection = TIMER_COUNTER_UP;//向上計數(shù)timer_initpara.period = 225-1;//定時周期timer_init(SIN_TIM,&timer_initpara);//定時器主輸出觸發(fā)源選擇timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定時器更新事件使能timer_update_event_enable(SIN_TIM); }/*操作函數(shù)*/ void sin_app(void) {//*配置*/sin_config();//DMA功能配置sin_dma_function_config();// TIMER觸發(fā)功能配置sin_timx_trigger_function_config();// TIMER啟動timer_enable(SIN_TIM);}bsp_dac.h文件
#include "gd32f30x.h"void sin_app(void);總結(jié)
以上是生活随笔為你收集整理的GD32F307 DAC 输出波形的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: MTK芯片介绍
- 下一篇: 税务信息系统建设安全管理平台的研究(一)
