STM32F4xx系列提供的DAC模塊是12 位電壓輸出數模轉換器。DAC可以按 8 位或 12 位模式進行配置,并且可與DMA控制器配合使用。在 12 位模式下,數據可以采用左對齊或右對齊。DAC有兩個輸出通道,每個通道各有一個轉換器。在DAC雙通道模式下,每個通道可以單獨進行轉換;當兩個通道組合在一起同步執行更新操作時,也可以同時進行轉換??赏ㄟ^一個輸入參考電壓引腳VREF+(與ADC共享)來提高分辨率。
DAC通道框圖
DAC引腳
DAC通道使能
將 DAC_CR 寄存器中的相應 ENx 位置 1,即可接通對應 DAC 通道。經過一段啟動時間tWAKEUP 后,DAC 通道被真正使能。
注意:ENx 位只會使能模擬 DAC Channelx 宏單元。即使 ENx 位復位, DAC Channelx 數字接口仍處于使能狀態。
DAC輸出緩沖器使能
DAC 集成了兩個輸出緩沖器,可用來降低輸出阻抗并在不增加外部運算放大器的情況下直接驅動外部負載。通過 DAC_CR 寄存器中的相應 BOFFx 位,可使能或禁止各 DAC 通道輸出緩沖器。
DAC數據格式
DAC同ADC一樣,數據分為8 位右對齊、12 位左對齊和12 位右對齊,為方便數據寫入和精度要求,一般采用12 位右對齊格式。
DAC轉換
DAC_DORx 無法直接寫入,任何數據都必須通過加載 DAC_DHRx 寄存器(寫入DAC_DHR8Rx、DAC_DHR12Lx、DAC_DHR12Rx、DAC_DHR8RD、DAC_DHR12LD 或DAC_DHR12LD)才能傳輸到 DAC 通道 x。
如果未選擇硬件觸發(DAC_CR 寄存器中的 TENx 位復位),那么經過一個 APB1 時鐘周期后,DAC_DHRx 寄存器中存儲的數據將自動轉移到 DAC_DORx 寄存器。但是,如果選擇硬件觸發(置位 DAC_CR 寄存器中的 TENx 位)且觸發條件到來,將在三個 APB1 時鐘周期后進行轉移。
當 DAC_DORx 加載了 DAC_DHRx 內容時,模擬輸出電壓將在一段時間 t SETTLING 后可用,具體時間取決于電源電壓和模擬輸出負載。
DAC輸出電壓
經過線性轉換后,數字輸入會轉換為0到VREF+之間的輸出電壓。
各DAC通道引腳的模擬輸出電壓通過以下公式確定:
DACoutput = VREF* DOR/4095
DAC觸發選擇
如果 TENx 控制位置 1,可通過外部事件(定時計數器、外部中斷線)觸發轉換。TSELx[2:0]控制位將決定通過 8 個可能事件中的哪一個來觸發轉換,如下表所示:
每當 DAC 接口在所選定時器 TRGO 輸出或所選外部中斷線 9 上檢測到上升沿時,DAC_DHRx寄存器中存儲的最后一個數據即會轉移到DAC_DORx 寄存器中。發生觸發后再經過三個APB1 周期,DAC_DORx 寄存器將會得到更新。
如果選擇軟件觸發,一旦 SWTRIG 位置 1,轉換即會開始。DAC_DHRx 寄存器內容加載到DAC_DORx 寄存器中后,SWTRIG 即由硬件復位。
DMA請求
每個 DAC 通道都具有 DMA 功能。兩個 DMA 通道用于處理 DAC 通道的 DMA 請求。這里不做詳細介紹。
生成波形
可以根據需要,配置相應的寄存器生成噪聲、三角波,也可以不生成波形。
下面了解下DAC相關的寄存器:
DAC 控制寄存器 (DAC_CR)
位 29 DMAUDRIE2:DAC 2 通道 DMA 下溢中斷使能 (DAC channel2 DMA underrun interrupt enable)
此位由軟件置 1 和清零。
0:禁止 DAC 2 通道 DMA 下溢中斷
1:使能 DAC 2 通道 DMA 下溢中斷
位 28 DMAEN2:DAC 2 通道 DMA 使能 (DAC channel2 DMA enable)
此位由軟件置 1 和清零。
0:禁止 DAC 2 通道 DMA 模式
1:使能 DAC 2 通道 DMA 模式
位 27:24 MAMP2[3:0]:DAC 2 通道掩碼/振幅選擇器 (DAC channel2 mask/amplitude selector)
這些位由軟件寫入,用于在生成噪聲波模式下選擇掩碼,或者在生成三角波模式下選擇振幅。
0000:不屏蔽 LFSR 的位 0/三角波振幅等于 1
0001:不屏蔽 LFSR 的位 [1:0]/三角波振幅等于 3
0010:不屏蔽 LFSR 的位 [2:0]/三角波振幅等于 7
0011:不屏蔽 LFSR 的位 [3:0]/三角波振幅等于 15
0100:不屏蔽 LFSR 的位 [4:0]/三角波振幅等于 31
0101:不屏蔽 LFSR 的位 [5:0]/三角波振幅等于 63
0110:不屏蔽 LFSR 的位 [6:0]/三角波振幅等于 127
0111:不屏蔽 LFSR 的位 [7:0]/三角波振幅等于 255
1000:不屏蔽 LFSR 的位 [8:0]/三角波振幅等于 511
1001:不屏蔽 LFSR 的位 [9:0]/三角波振幅等于 1023
1010:不屏蔽 LFSR 的位 [10:0]/三角波振幅等于 2047
=1011:不屏蔽 LFSR 的位 [11:0]/三角波振幅等于 4095
位 23:22 WAVE2[1:0]:DAC 2 通道噪聲/三角波生成使能 (DAC channel2 noise/triangle wave generation enable)
這些位由軟件置 1 或清零。
00:禁止生成波
01:使能生成噪聲波
1x:使能生成三角波
注意:只在位 TEN2 = 1 (使能 DAC 2 通道觸發)時使用
位 21:19 TSEL2[2:0]:DAC 2 通道觸發器選擇 (DAC channel2 trigger selection)
這些位用于選擇 DAC 2 通道的外部觸發事件
000:定時器 6 TRGO 事件
001:定時器 8 TRGO 事件
010:定時器 7 TRGO 事件
011:定時器 5 TRGO 事件
100:定時器 2 TRGO 事件
101:定時器 4 TRGO 事件
110:外部中斷線 9
111:軟件觸發
注意:只在位 TEN2 = 1 (使能 DAC 2 通道觸發)時使用。
位 18 TEN2:DAC 2 通道觸發使能 (DAC channel2 trigger enable)
此位由軟件置 1 和清零,以使能/禁止 DAC 2 通道觸發
0:禁止 DAC 2 通道觸發,寫入 DAC_DHRx 寄存器的數據在一個 APB1 時鐘周期之后轉移到 DAC_DOR2 寄存器
1:使能 DAC 2 通道觸發,DAC_DHRx 寄存器的數據在三個 APB1 時鐘周期之后轉移到DAC_DOR2 寄存器
注意:如果選擇軟件觸發,DAC_DHRx 寄存器 的內容只需一個 APB1 時鐘周期即可轉移到DAC_DOR2 寄存器。
位 17 BOFF2:DAC 2 通道輸出緩沖器禁止 (DAC channel2 output buffer disable)
此位由軟件置 1 和清零,以使能/禁止 DAC 2 通道輸出緩沖器。
0:使能 DAC 2 通道輸出緩沖器
1:禁止 DAC 2 通道輸出緩沖器
位 16 EN2:DAC 2 通道使能 (DAC channel2 enable)
此位由軟件置 1 和清零,以使能/禁止 DAC 2 通道。
0:禁止 DAC 2 通道
1:使能 DAC 2 通道
位 13 DMAUDRIE1:DAC 1 通道 DMA 下溢中斷使能 (DAC channel1 DMA Underrun Interrupt enable)
此位由軟件置 1 和清零。
0:禁止 DAC 1 通道 DMA 下溢中斷
1:使能 DAC 1 通道 DMA 下溢中斷
位 12 DMAEN1:DAC 1 通道 DMA 使能 (DAC channel1 DMA enable)
此位由軟件置 1 和清零。
0:禁止 DAC 1 通道 DMA 模式
1:使能 DAC 1 通道 DMA 模式
位 11:8 MAMP1[3:0]:DAC 1 通道掩碼/振幅選擇器 (DAC channel1 mask/amplitude selector)
這些位由軟件寫入,用于在生成噪聲波模式下選擇掩碼,或者在生成三角波模式下選擇振幅。
0000:不屏蔽 LFSR 的位 0/三角波振幅等于 1
0001:不屏蔽 LFSR 的位 [1:0]/三角波振幅等于 3
0010:不屏蔽 LFSR 的位 [2:0]/三角波振幅等于 7
0011:不屏蔽 LFSR 的位 [3:0]/三角波振幅等于 15
0100:不屏蔽 LFSR 的位 [4:0]/三角波振幅等于 31
0101:不屏蔽 LFSR 的位 [5:0]/三角波振幅等于 63
0110:不屏蔽 LFSR 的位 [6:0]/三角波振幅等于 127
0111:不屏蔽 LFSR 的位 [7:0]/三角波振幅等于 255
1000:不屏蔽 LFSR 的位 [8:0]/三角波振幅等于 511
1001:不屏蔽 LFSR 的位 [9:0]/三角波振幅等于 1023
1010:不屏蔽 LFSR 的位 [10:0]/三角波振幅等于 2047
=1011:不屏蔽 LFSR 的位 [11:0]/三角波振幅等于 4095
位 7:6 WAVE1[1:0]:DAC 1 通道噪聲/三角波生成使能 (DAC channel1 noise/triangle wave generation enable)
這些位將由軟件置 1 和清零。
00:禁止生成波
01:使能生成噪聲波
1x:使能生成三角波
注意:只在位 TEN1 = 1 (使能 DAC 1 通道觸發)時使用。
位 5:3 TSEL1[2:0]:DAC 1 通道觸發器選擇 (DAC channel1 trigger selection)
這些位用于選擇 DAC 1 通道的外部觸發事件。
000:定時器 6 TRGO 事件
001:定時器 8 TRGO 事件
010:定時器 7 TRGO 事件
011:定時器 5 TRGO 事件
100:定時器 2 TRGO 事件
101:定時器 4 TRGO 事件
110:外部中斷線 9
111:軟件觸發
注意:只在位 TEN1 = 1 (使能 DAC 1 通道觸發)時使用。
位 2 TEN1:DAC 1 通道觸發使能 (DAC channel1 trigger enable)
此位由軟件置 1 和清零,以使能/禁止 DAC 1 通道觸發。
0:禁止 DAC 1 通道觸發,寫入 DAC_DHRx 寄存器的數據在一個 APB1 時鐘周期之后轉移到 DAC_DOR1 寄存器
1:使能 DAC 1 通道觸發,DAC_DHRx 寄存器的數據在三個 APB1 時鐘周期之后轉移到DAC_DOR1 寄存器
注意:如果選擇軟件觸發, DAC_DHRx 寄存器的內容只需一個 APB1 時鐘周期即可轉移到DAC_DOR1 寄存器。
位 1 BOFF1:DAC 1 通道輸出緩沖器禁止 (DAC channel1 output buffer disable)
此位由軟件置 1 和清零,以使能/禁止 DAC 1 通道輸出緩沖器。
0:使能 DAC 1 通道輸出緩沖器
1:禁止 DAC 1 通道輸出緩沖器
位 0 EN1:DAC 1 通道使能 (DAC channel1 enable)
此位由軟件置 1 和清零,以使能/禁止 DAC 1 通道。
0:禁止 DAC 1 通道
1:使能 DAC 1 通道
DAC 軟件觸發寄存器 (DAC_SWTRIGR)
位 1 SWTRIG2:DAC 2 通道軟件觸發 (DAC channel2 software trigger)
此位由軟件置 1 和清零,以使能/禁止軟件觸發。
0:禁止軟件觸發
1:使能軟件觸發
注意:一旦 DAC_DHR2 寄存器值加載到 DAC_DOR2 寄存器中,該位即會由硬件清零(一個APB1 時鐘周期之后)。
位 0 SWTRIG1:DAC 1 通道軟件觸發 (DAC channel1 software trigger)
此位由軟件置 1 和清零,以使能/禁止軟件觸發。
0:禁止軟件觸發
1:使能軟件觸發
注意:一旦 DAC_DHR1 寄存器值加載到 DAC_DOR1 寄存器中,該位即會由硬件清零(一個APB1 時鐘周期之后)。
DAC 1 通道 12 位右對齊數據保持寄存器 (DAC_DHR12R1)
位 11:0 DACC1DHR[11:0]:DAC 1 通道 12 位右對齊數據 (DAC channel1 12-bit right-aligned data)
這些位由軟件寫入,用于為 DAC 1 通道指定 12 位數據。
下面開始編寫DAC1初始化函數和數據寫入函數
void DAC1_Init()
{
//1. 開PA時鐘
RCC- >AHB1ENR |= 1< 0;
//2. 模式:模擬
GPIOA- >MODER |= 3< 8;
//3. 開DAC1時鐘(DAC1和DAC2共用一個時鐘)
RCC- >APB1ENR |= 1< 29;
DAC- >CR &= 0XFFFF0000;
DAC- >CR |= 7< 3; //軟件觸發,不生產波形
DAC- >CR |= 0< 1; //使能輸出緩沖驅動器
DAC- >CR |= 1< 0; //使能通道
Delay_us(10);
}
//使能軟件觸發函數
//一旦 DAC_DHR1寄存器值加載到DAC_DOR1寄存器中,該位即會由硬件清零(一個APB1時鐘周期之后)
void DAC1_Trigger()
{
DAC- >SWTRIGR |= 1< 0;
}
//把數據寫入12位右對齊數據保持寄存器
void DAC1_SendDat(u16 *dat)
{
DAC- >DHR12R1 = *dat;
}
接下來編寫測試函數
u16 DAC_buf[1024] = {0};
void DAC1_GetSine()//把DAC_buf賦值為正弦波的數組,用于模擬呼吸燈
{
u16 i = 0;
for(i=0;i< 256;i++) //0-π/2
{
DAC_buf[i] = (u16)((1.65+1.65*sin(3.14/512*i))*4096/3.3);
}
for(i=1;i<=256;i++) //π/2~π
{
DAC_buf[255+i] = DAC_buf[256-i];
}
for(i=1;i< 256;i++) //π~3/2π
{
DAC_buf[511+i] = 4096 - DAC_buf[i];
}
for(i=1;i< 256;i++) //3/2π~2π
{
DAC_buf[767+i] = DAC_buf[768-i];
}
}
#include "stm32f4xx.h"
#include "delay.h"
#include "math.h"
#include "dac.h"
int main()
{
u32 i=0;
DAC1_Init();
DAC1_GetSine();
while(1)
{
for(i=0;i< 1024;i++)
{
DAC1_SendDat(&DAC_buf[i]);
DAC1_Trigger();
Delay_ms(5);
}
}
}
對于STM32來說,并不是所有型號都有;就算有DAC,資源也非常有限。而STM32所有的芯片都有PWM輸出,并且PWM輸出通道很多,資源豐富。因此,我們可以使用PWM來實現DAC的輸出從而節省成本。
評論
查看更多