日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GD32F307 DAC 输出波形

發布時間:2023/12/20 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GD32F307 DAC 输出波形 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • DAC
      • DAC_CTL 控制寄存器
    • 定時器
      • TIMERx_CTL1 控制寄存器
      • 改變波形頻率
    • DMA
      • DMA和外設配合
      • DMA_CHxCNT計數寄存器
    • 波形曲線
    • 總結
    • 源碼

DAC

如下面框圖所示,使能外部觸發后(通過設置 DAC_CTL 寄存器的 DTENx 位), 當已經選擇的觸發事件發
生, DAC 保持數據(DACx_DH)會被轉移到 DAC 數據輸出寄存器(DACx_DO),經過一段時間之后,模擬輸出變得有效。DAC引腳上的模擬輸出電壓DACoutput=VREF×DAC_DO/4096。

對于12位的DAC保持數據(DACx_DH),可以通過對DACx_R12DH、DACx_L12DH和DACx_R8DH中的任意一個寄存器寫入數據來配置。

在外部觸發使能的情況下,通過設置DAC_CTL寄存器的DDMAENx位來使能DMA請求。當有外部硬件觸發的時候(不是軟件觸發),則產生一個DMA請求。

DAC_CTL 控制寄存器

名稱描述
DWBW0[3:0]DAC0 噪聲波位寬
DDMAEN0DAC0 DMA 使能
DWM0[1:0]DAC0 噪聲波模式
DTSEL0[2:0]DAC0 觸發選擇
DBOFF0DAC0 輸出緩沖區
DEN0DAC0 使能
DTEN0DAC0 觸發使能

配置DAC其實還是配置的上面這些東西,只不過,代碼里面是調用了固件庫函數來配的。

其中在DAC0外部觸發使能(DTEN0=1)的情況下,DAC0外部觸發源選擇TIMER6 TRGO。

/*DAC通道輸出配置,定時器6觸發,不開啟輸出緩存*/ static void sin_adc_channel_config(void) {//DAC外設復位dac_deinit();/* DAC觸發禁能 */dac_trigger_disable(SIN_DAC);//DAC噪聲波模式選擇dac_wave_mode_config(SIN_DAC, DAC_WAVE_DISABLE);//DAC輸出緩沖區禁能dac_output_buffer_disable(SIN_DAC);/* DAC觸發源的選擇*/dac_trigger_source_config(SIN_DAC,DAC_TRIGGER_T6_TRGO);/* DAC的DMA功能使能 */dac_dma_enable(SIN_DAC);/* DAC觸發使能 */dac_trigger_enable(SIN_DAC);/* DAC使能 */dac_enable(SIN_DAC); }

定時器

選用基本定時器TIM6觸發DAC。

如下面框圖所示,TIMER_CK驅動計數器預分頻器,預分頻值由TIMERx_PSC寄存器確定,TIMER_CK經過預分頻器產生PSC_CLK。向上計數模式下,計數器從0開始向上連續計數到自動加載值(在TIMERx_CAR寄存器中),然后,重新從0開始向上計數并產生上溢事件。此時,如果TIMERx_SWEVG寄存器的UPG位置1,計數值會被清0,并產生更新事件。發生更新事件時,所有的寄存器(重復計數器,自動重載寄存器,預分頻寄存器)都將被更新。

TIMERx_CTL1 控制寄存器

其中MMC[2:0]位控制TRGO信號的選擇,使用timer_master_output_trigger_source_select函數,主模式控制器選擇更新事件作為TRGO。

使用timer_update_event_enable函數,將TIMERx_SWEVG寄存器的UPG位置1,那么定時器產生上溢事件時會產生更新事件,然后觸發TIMERx_TRGO。進而觸發DAC。

//定時器主輸出觸發源選擇timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定時器更新事件使能timer_update_event_enable(SIN_TIM);

改變波形頻率

這里面,設置不同的定時周期,會改變輸出波形的頻率。
按照下面這樣設置,最終會得到4KHZ的正弦波。

/*TIMx觸發配置*/ 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;//預分頻timer_initpara.counterdirection = TIMER_COUNTER_UP;//向上計數timer_initpara.period = 225-1;//定時周期timer_init(SIN_TIM,&timer_initpara);//定時器主輸出觸發源選擇timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定時器更新事件使能timer_update_event_enable(SIN_TIM); }

DMA

DMA控制器提供了一種硬件的方式,在外設和存儲器之間或者存儲器和存儲器之間傳輸數據。無需CPU的介入,使CPU可以專注在處理其他系統功能上。

DMA傳輸 ,從源地址讀取數據后,將讀取的數據存儲到目的地址。

AHB從接口配置DMA,AHB主接口進行數據傳輸,仲裁器進行DMA請求的優先級管理。

dma_parameter_struct結構體:

名稱描述
periph_addr外設基地址
periph_width外設數據傳輸寬度
memory_addr存儲器基地址
memory_width存儲器數據傳輸寬度
numberDMA通道數據傳輸數量
priorityDMA通道傳輸軟件優先級
periph_inc外設地址生成算法模式
memory_inc存儲器地址生成算法模式
directionDMA通道數據傳輸方向

初始化,設定上面結構體的值,其實還是對DMA_CHxCTL寄存器的一些設置。設置傳輸方向為從存儲器讀出并寫入外設。

存儲器和外設都獨立的支持兩種地址生成算法:固定模式和增量模式。寄存器DMA_CHxCTL的PNAGA和MNAGA位用來設置存儲器和外設的地址生成算法,固定模式中,地址一直固定為初始化的基地址,增量模式中,下一次傳輸數據的地址是當前地址加1(或2、4,取決于數據傳輸寬度) ,前面波形數組uint16_t Sine[POINT_NUM2]定義的是U16,所以設置的寬度也是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和外設配合

循環模式用來處理連續的外設請求,循環模式中,當每次DMA傳輸完成后,CNT值會被重新載入,且傳輸完成標志位會被置1。
DMA會一直響應外設的請求,直到通道使能位(DMA_CHxCTL寄存器的CHEN位)被清0。

當DMA控制器在同一時間接收到多個外設請求時,仲裁器將根據外設請求的優先級來決定響應哪一個外設請求。當通道具有相同的軟件優先級時,編號低的通道優先級高。

多個外設請求被映射到同一個DMA 通道。這些請求信號在經過邏輯或后進入DMA。通過配置對應外設的寄存器,每個外設
的請求均可以獨立的開啟或關閉。DMA1各通道請求表如下,由于外設是DAC_CH0,所以選用DMA1的Channel2通道。

為了保證數據的有效傳輸, DMA控制器中引入了外設和存儲器的握手機制。請求信號由外設發出,表明外設已經準備好發送或接收數據,應答信號由DMA控制器響應,表明DMA控制器已經發送AHB命令去訪問外設。

DMA_CHxCNT計數寄存器

CNT[15:0],該寄存器表明還有多少數據等待被傳輸。一旦通道使能,該寄存器為只讀的,并在每個DMA傳輸之后值減1。如果該寄存器的值為0,無論通道開啟與否,都不會有數據傳輸。如果該通道工作在循環模式下,一旦通道的傳輸任務完成,該寄存器會被自動重裝載為初始設置值。程序中,用dma_transfer_number_config函數配置該寄存器的值。

#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還有多少數據要傳輸dma_transfer_number_config(SIN_DMA,SIN_DMA_CHANNEL,ARRAYNUM(Sine));//DMAx的通道y的外設基地址配置dma_periph_address_config(SIN_DMA,SIN_DMA_CHANNEL,DAC0_R12DH_ADDRESS);//DMA循環模式開啟dma_circulation_enable(SIN_DMA, SIN_DMA_CHANNEL);//DMA的通道使能dma_channel_enable(SIN_DMA, SIN_DMA_CHANNEL); }

外設基地址配置:

DAC0_R12DH地址偏移: 0x08

DAC 基地址: 0x4000 7400

DAC0_R12DH地址:0x4000 7408

波形曲線

其中可以修改點數,使波形變得平滑;也可以修改波形幅值;也可以修改波形形狀。

#! python3 #coding=utf-8import matplotlib.pyplot as plt import numpy as np import math#修改本變量可以更改點數,如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:#調整幅值至在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()

如果得到的值為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 };

效果如下。

總結

1.使能TIM6觸發DAC,其中,將TIMERx_SWEVG寄存器的UPG位置1,定時器產生上溢事件時會產生更新事件,主模式控制器選擇更新事件作為TRGO。由于設置了DAC的DAC_CTL寄存器的DDMAENx位來使能DMA請求,當有外部硬件觸發的時候,DAC則產生一個DMA請求。

3.使用DMA傳輸數據,從存儲器讀出數據并寫入外設,也就是說,DMA從Sine數組的地址讀數據,寫到DAC0_R12DH寄存器里面。

2.觸發事件發生, DAC保持數據(DACx_DH)會被轉移到DAC數據輸出寄存器(DACx_DO),經過一段時間之后,DAC引腳上的輸出電壓DACoutput=VREF×DAC_DO/4096。

4.總而言之,定時器從0開始向上連續計數到自動加載值,然后,重新從0開始向上計數并產生上溢事件,TIMERx_SWEVG寄存器的UPG位置1,計數值會被清0,并產生更新事件,主模式控制器選擇更新事件作為TRGO,觸發DAC,產生DMA請求,搬運數組的數據。由于DMA設置為循環模式,當每次DMA傳輸完成后,CNT值(待傳輸的數據個數)會被重新載入,DMA會一直響應外設的請求,如此循環往復,把波形曲線的值寫到DAC0_R12DH寄存器里面,然后在DAC引腳上輸出電壓,DACoutput=VREF×DAC_DO/4096。

5.使用一個外設,看用戶手冊,可以知道外設大概都有哪些功能,要使用外設的某些功能都需要怎么配置寄存器。寫程序的話,可能提供庫函數,庫函數就是把配置寄存器的那些代碼給封裝起來了,然后使用庫函數把外設用起來就好了。

源碼

GD32F307DAC輸出波形-單片機文檔類資源-CSDN文庫
bsp_dac.c文件如下

main.c調用void sin_app(void)函數即可。

#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觸發,不開啟輸出緩存*/ 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觸發源的選擇*/dac_trigger_source_config(SIN_DAC,DAC_TRIGGER_T6_TRGO);/* DAC的DMA功能使能 */dac_dma_enable(SIN_DAC);/* DAC觸發使能 */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還有多少數據要傳輸dma_transfer_number_config(SIN_DMA,SIN_DMA_CHANNEL,ARRAYNUM(Sine));//DMAx的通道y的外設基地址配置dma_periph_address_config(SIN_DMA,SIN_DMA_CHANNEL,DAC0_R12DH_ADDRESS);//DMA循環模式開啟dma_circulation_enable(SIN_DMA, SIN_DMA_CHANNEL);//DMA的通道使能dma_channel_enable(SIN_DMA, SIN_DMA_CHANNEL); }/*TIMx觸發配置*/ 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;//預分頻timer_initpara.counterdirection = TIMER_COUNTER_UP;//向上計數timer_initpara.period = 225-1;//定時周期timer_init(SIN_TIM,&timer_initpara);//定時器主輸出觸發源選擇timer_master_output_trigger_source_select(SIN_TIM,TIMER_TRI_OUT_SRC_UPDATE);//定時器更新事件使能timer_update_event_enable(SIN_TIM); }/*操作函數*/ void sin_app(void) {//*配置*/sin_config();//DMA功能配置sin_dma_function_config();// TIMER觸發功能配置sin_timx_trigger_function_config();// TIMER啟動timer_enable(SIN_TIM);}

bsp_dac.h文件

#include "gd32f30x.h"void sin_app(void);

總結

以上是生活随笔為你收集整理的GD32F307 DAC 输出波形的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。