13.1 介紹一下
數字量轉換成模擬量的過程叫做數模轉換,完成這種功能的電路叫做數模轉換器。說白了就是將離散的數字信號轉換為連續變量的模擬信號的一種器件。
這玩意主要由數字寄存器、模擬電子開關、位權網絡、求和運算放大器和基準電壓源(或恒流源)等組成的。主要用存于數字寄存器的數字量的各位數碼,分別控制對應位的模擬電子開關,使數碼為1的位在位權網絡上產生與其位權成正比的電流值,再由運算放大器對各電流值求和,并轉換成電壓值 。
換成圖也就是下面這個小東西:
STM32F429內部含有兩個12 位電壓輸出數模轉換器。DAC 可以按 8 位或 12 位模式進行配置,而且也是可以和DMA配合使用的,在12位模式中,數據可以是左對齊也可以是右對齊。
DAC 有兩個輸出通道,每個通道各有一個轉換器。
兩個 DAC 轉換器:各對應一個輸出通道:
12 位模式下數據采用左對齊或右對齊
生成噪聲波、生成三角波
DAC 雙通道單獨或同時轉換
每個通道都具有 DMA 功能
通過外部觸發信號進行轉換
DAC 各個引腳功能定義:
13.3 STM32f429 DAC功能
1、DAC 轉換
兩個DAC分別對應一個獨立的通道,當使用時需要將 DAC_CR 寄存器中的相應 ENx 位置 1,即可使能對應 DAC 通道。
在使能DAC通道之后,可以通過寫DAC_DHRx 寄存器或通過觸發信號來啟動一次DAC轉換。
(1)寫DAC_DHRx 寄存器啟動DAC轉換
如果未選擇硬件觸發(DAC CR中的TENx位復位),那么經過一個APB1時鐘周期后,DAC_DHRx中存儲的數據將自動轉移到DAC_DORx。當DAC_DORx加載了DAC_DHRx內容時,模擬輸出電壓將在一段時間t_SETTING后可用,具體時間取決于電源電壓和模擬輸出負載。
DAC_DORx 無法直接寫入,任何數據都必須通過加載DAC_DHRx 寄存器才能傳輸到 DAC 通道x。
(2)硬件觸發啟動DAC轉換
如果選擇硬件觸發(置位 DAC_CR 寄存器中的 TENx 位)可通過外部事件(定時計數器、外部中斷線)觸發轉換。
當觸發條件到來,將在三個APB1時鐘周期后,將DAC_DHRx 寄存器的內容轉移到DAC_DORx寄存器。
DAC外部觸發源:
2、DAC 數據格式
1)對于 DAC 單通道 x,有三種可能的方式:
8位右對齊:軟件必須將數據加載到 DAC_DHR8Rx [7:0] 位(存儲到DHRx[11:4] 位)。
12位左對齊:軟件必須將數據加載到 DAC_DHR12Lx [15:4] 位(存儲到DHRx[11:0] 位)。
12 位右對齊:軟件必須將數據加載到 DAC_DHR12Rx [11:0] 位(存儲到DHRx[11:0] 位)。
DAC單通道數據對齊方式(下圖):
2)對于 DAC雙通道 x,有三種可能的方式:
8 位右對齊:將 DAC 1 通道的數據加載到 DAC_DHR8RD [7:0] 位(存儲到DHR1[11:4] 位),將 DAC 2 通道的數據加載到 DAC_DHR8RD [15:8] 位(存儲到 DHR2[11:4] 位)
12 位左對齊:將 DAC 1 通道的數據加載到 DAC_DHR12RD [15:4] 位(存儲到 DHR1[11:0] 位),將 DAC 2 通道的數據加載到 DAC_DHR12RD [31:20] 位(存儲到 DHR2[11:0] 位)
12 位右對齊:將 DAC 1 通道的數據加載到 DAC_DHR12RD [11:0] 位(存儲到 DHR1[11:0] 位),將 DAC 2 通道的數據加載到 DAC_DHR12RD [27:16] 位(存儲到 DHR2[11:0] 位)
3、DMA 請求
每個 DAC 通道都具有 DMA 功能。兩個 DMA 通道用于處理 DAC 通道的 DMA 請求。
4、生成噪聲
將 WAVEx[1:0] 置為 “01”即可選擇生成噪聲,使用 LFSR(線性反饋移位寄存器)可以生成可變振幅的偽噪聲。
LFSR中的預加載值為0xAAA。
5、生成三角波
將 WAVEx[1:0] 置為“10”即可選擇 DAC 生成三角波。
6、DAC 雙通道轉換
DAC控制器有三個雙寄存器:DHR8RD、DHR12RD 和 DHR12LD,可以訪問一個寄存器同時驅動兩個 DAC 通道,從而有效利用兩個 DAC 通道總線帶寬。通過兩個DAC 通道和這三個雙寄存器可以實現 11 種轉換模式:
獨立觸發(不產生波形)
獨立觸發(生成單個 LFSR)
獨立觸發(生成不同 LFSR)
獨立觸發(生成單個三角波)
獨立觸發(生成不同三角波)
同步軟件啟動
同步觸發(不產生波形)
同步觸發(生成單個 LFSR)
同步觸發(生成不同 LFSR)
同步觸發(生成單個三角波)
同步觸發(生成不同三角波)
13.4 DAC典型應用步驟
1、使能DAC時鐘:
開啟PA口時鐘和ADC1時鐘,設置PA1為模擬輸入。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
使能模擬信號輸入GPIO時鐘,假設是GPIOA,根據實際情況調整:
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
2、初始化模擬信號輸入的GPIO引腳為模擬方式:
GPIO_Init();
3、初始化DAC通道參數。
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct) ;
4、使能DAC通道
void DAC_Cmd(uint32_t DAC_Channel, FunctionalState NewState);
5、啟動DAC轉換
(1)通過寫DAC_DHRx 寄存器啟動DAC轉換:
void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data) ;
或void DAC_SetChannel2Data(uint32_t DAC_Align, uint16_t Data) ;
或void DAC_SetDualChannelData(uint32_t DAC_Align, uint16_t Data2, uint16_t Data1) ;
或者通過觸發信號啟動DAC轉換
13.5 常用庫函數
DAC相關的函數和宏都被定義在兩個文件中:
頭文件:stm32f4xx_dac.h
源文件:stm32f4xx_dac.c
1、DAC初始化函數
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct);
參數1:uint32_t DAC_Channel,是DAC通道宏定義,定義在stm32f4xx_dac.h中:
#define DAC_Channel_1 ((uint32_t)0x00000000) //通道1
#define DAC_Channel_2 ((uint32_t)0x00000010) //通道2
參數2:DAC_InitTypeDef* DAC_InitStruct,是DAC初始化結構體指針,自定義的結構體定義在stm32f4xx_dac.h中:
typedef struct
{
uint32_t DAC_Trigger; //設置觸發方式
uint32_t DAC_WaveGeneration; // 設置波形生成
uint32_t DAC_LFSRUnmask_TriangleAmplitude; //設置LFSR掩碼值或三角波最大振幅
uint32_t DAC_OutputBuffer; //設置輸出緩沖器
}DAC_InitTypeDef;
例如:
DAC_InitTypeDef DAC_InitStructure;
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;//不使用觸發方式,軟件啟動轉換
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //不使用波形發生器
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //不使用DAC輸出緩沖
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽幅值
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
2、DAC使能函數
void DAC_Cmd(uint32_t DAC_Channel, FunctionalState NewState);
參數1:uint32_t DAC_Channel,DAC通道宏定義。
參數2:FunctionalState
NewState,使能或禁止ADC,定義如下:
ENABLE:使能ADC;
DISABLE:禁止ADC。
3、單通道輸出,寫DAC通道1輸出數據寄存器函數
void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data) ;
參數1:uint32_t DAC_Align, DAC數據對齊方式,定義如下:
#define DAC_Align_12b_R ((uint32_t)0x00000000)//12位右對齊形式
#define DAC_Align_12b_L ((uint32_t)0x00000004) //12位左對齊形式
#define DAC_Align_8b_R ((uint32_t)0x00000008) //8位右對齊形式
參數2:uint16_t Data,DAC輸出的數據。
4、單通道輸出,寫DAC通道2輸出數據寄存器函數
void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data) ;
void DAC_Cmd(uint32_t DAC_Channel, FunctionalState NewState);
5、雙通道輸出,寫DAC輸出數據寄存器函數
void DAC_SetDualChannelData(uint32_t DAC_Align, uint16_t Data2, uint16_t Data1) ;
參數1:同單通道輸出定義形式。
參數2和參數3:DAC通道2和DAC通道1輸出數據。
6、DAC軟件觸發函數
void DAC_SoftwareTriggerCmd(uint32_t DAC_Channel, FunctionalState NewState)
參數1:uint32_t DAC_Channel,DAC通道宏定義。
參數2:FunctionalState NewState,使能或禁止ADC。
13.6 應用
使用DAC通道1生成一個頻率為1KHz的正弦波。
使用定時器T2,在每次定時溢出中斷中采樣數組數據,并寫入DAC_DHRx,定時溢出頻率為20KHz。
DAC使用單通道模式,輸出不使用觸發,使能輸出緩沖功能。在每次將數據寫入DAC_DHRx后,經過一個APB1 時鐘周期,DAC_DHRx 寄存器中存儲的數據將自動轉移到DAC_DORx,經輸出緩沖器,在PA4引腳上產生對應輸出電壓。
1、編程要點
(1)、使能DAC和復用引腳GPIO的工作時鐘。
(2)、初始化DAC通道1相關GPIO引腳為模擬方式。
(3)、根據要求,初始化ADC1。
(4)、初始化定時器
(5)、使能DAC。
(6)、在定時器一處中斷中寫DAC_DHRx。
2、DAC初始化功能
#include
#define Pi 3.1415926
#define f 1000//正弦波頻率 1KHz
#define fs 20000//采樣頻率 20KHz
uint16_t Sine_Table[20];
void DAC_Config (void)
{
uint16_t i = 0;
/* 生成正弦波形數據,右對齊*/
for (i = 0; i < 20; i++)
{
Sine_Table [i] = (uint16_t )((float)4095*(1+sin(2iPi* f /fs))/2);
}
DAC_Mode_Init ();//配置DAC功能
TIM_Config();//配置定時器功能
}
3、DAC配置程序
static void DAC_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitStructure;
/ -------------------第1步-------------------- /
/* 使能GPIOA時鐘 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* 使能DAC時鐘 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
/ -------------------第2步-------------------- /
/* DAC的GPIO配置,模擬 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/ -------------------第3步-------------------- /
/* 配置DAC 通道1 */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;//不使用觸發
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //不使用波形發生器
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //使用DAC輸出緩沖
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0; //屏蔽幅值 設置
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
/ -------------------第4步-------------------- /
/* 使能通道1 由PA4輸出 */
DAC_Cmd(DAC_Channel_1, ENABLE);
}
4、定時器配置程序
static void TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能TIM2時鐘,TIM2CLK 為90M */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* TIM2基本定時器配置 */
// TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 4500-1; //采樣頻率 = 20KHz
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //預分頻,不分頻 90M / (0+1) = 90M
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時鐘分頻系數
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* 配置TIM2中斷 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update,ENABLE);
/* 使能TIM2 */
TIM_Cmd(TIM2, ENABLE);
}
5、定時器中斷服務程序
void TIM2_IRQHandler(void)
{
static u16 Index;
if(TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
if(Index <19)//采樣邊界控制
Index ++;
else
Index =0;
//寫DAC通道1的12位右對齊數據寄存器,從而啟動一次DAC轉換
DAC_SetChannel1Data(DAC_Align_12b_R, Sine_Table [Index]);
}
}
具體的可以參考其他官方或個人優秀的代碼。
評論
查看更多