DAC相关
DAC簡介
DAC為數字/模擬轉換模塊,故名思議,它的作用就是把輸入的數字編碼,轉換成對應的模擬電壓輸出,它的功能與ADC相反。 在常見的數字信號系統中,大部分傳感器信號被化成電壓信號,而ADC把電壓模擬信號轉換成易于計算機存儲、處理的數字編碼, 由計算機處理完成后,再由DAC輸出電壓模擬信號,該電壓模擬信號常常用來驅動某些執行器件,使人類易于感知。如音頻信號的采集及還原就是這樣一個過程。
STM32具有片上DAC外設,它的分辨率可配置為8位或12位的數字輸入信號,具有兩個DAC輸出通道,這兩個通道互不影響, 每個通道都可以使用DMA功能,都具有出錯檢測能力,可外部觸發。
DAC功能框圖
整個DAC模塊圍繞框圖下方的“數字至模擬轉換器x”展開,它的左邊分別是參考電源的引腳:VDDA、 VSSA及Vref+, 其中STM32的DAC規定了它的參考電壓:math:V_{ref +}輸入范圍為2.4——3.3V。 “數字至模擬轉換器x”的輸入為DAC的數據寄存器“DORx”的數字編碼,經過它轉換得的模擬信號由圖中右側的“DAC_OUTx”輸出。 而數據寄存器“DORx”又受“控制邏輯”支配,它可以控制數據寄存器加入一些偽噪聲信號或配置產生三角波信號。圖中的左上角為DAC的觸發源, DAC根據觸發源的信號來進行DAC轉換,其作用就相當于DAC轉換器的開關,它可以配置的觸發源為外部中斷源觸發、定時器觸發或軟件控制觸發。 如本章實驗中需要控制正弦波的頻率,就需要定時器定時觸發DAC進行數據轉換。
參考電壓
與ADC外設類似,DAC也使用VREF+引腳作為參考電壓, 在設計原理圖的時候一般把VSSA接地,把VREF+和VDDA 接3.3V, 可得到DAC的輸出電壓范圍為:0~3.3V。
如果想讓輸出的電壓范圍變寬,可以在外部加一個電壓調理電路,把0~3.3V的DAC輸出抬升到特定的范圍即可。
數模轉換及輸出通道
框圖中的“數字至模擬轉換器x”是核心部件,整個DAC外設都圍繞它而展開。它以左邊的VREF+作為參考電源, 以DAC的數據寄存器“DORx”的數字編碼作為輸入,經過它轉換得的模擬信號由右側的“DAC_OUTx”通道輸出。其中各個部件中的“x”是指設備的標號, 在STM32中具有2個這樣的DAC部件,每個DAC有1個對應的輸出通道連接到特定的引腳,即:PA4-通道1,PA5-通道2,為避免干擾,使用DAC功能時, DAC通道引腳需要被配置成模擬輸入功能(AIN)。
觸發源及DHRx寄存器
在使用DAC時,不能直接對上述DORx寄存器寫入數據,任何輸出到DAC通道x的數據都必須寫入到DHRx寄存器中(其中包含DHR8Rx、DHR12Lx等, 根據數據對齊方向和分辨率的情況寫入到對應的寄存器中)。
數據被寫入到DHRx寄存器后,DAC會根據觸發配置進行處理,若使用硬件觸發,則DHRx中的數據會在3個APB1時鐘周期后傳輸至DORx, DORx隨之輸出相應的模擬電壓到輸出通道;若DAC設置為外部事件觸發,可以使用定時器(TIMx_TRGO)、 EXTI_9信號或軟件觸發(SWTRIGx)這幾種方式控制數據DAC轉換的時機,例如使用定時器觸發,配合不同時刻的DHRx數據,可實現DAC輸出正弦波的功能。
配置
(1) DAC_Trigger
用于配置DAC的觸發模式,當DAC產生相應的觸發事件時,才會把DHRx寄存器的值轉移到DORx寄存器中進行轉換。 本結構體成員可以選擇的觸發模式如下:硬件觸發模式(DAC_Trigger_None),DHRx寄存器內的數據會在3個APB1時鐘周期內自動轉換至DORx進行轉換; 定時器觸發模式(DAC_Trigger_T2/4/5/6/7/8_TRGO),使用定時器2、4、5、6、7、8控制DHRx寄存器的數據按時間轉移到DORx中進行轉換, 利用這種方式可以輸出特定的波形;EXTI_9觸發方式(DAC_Trigger_Ext_IT9),當產生EXTI_9事件時(如GPIO中斷事件),觸發轉換; 軟件觸發模式DAC_Trigger_Software,在本模式下,向DAC_SWTRIGR寄存器寫入配置即可觸發信號進行轉換。
(2) DAC_WaveGeneration
本成員用于設置是否使用DAC輸出偽噪聲或三角波(DAC_WaveGeneration_None/Noise/Triangle),使用偽噪聲和三角波輸出時, DAC都會把LFSR寄存器的值疊加到DHRx數值上,產生偽噪聲和三角波,若希望產生自定義的輸出時,直接配置為DAC_WaveGeneration_None即可。
(3) DAC_LFSRUnmask_TriangleAmplitude
本成員通過控制DAC_CR的MAMP2位設置LFSR寄存器位的數據,即當使用偽噪聲或三角波輸出時要疊加到DHRx的值,非噪聲或三角波輸出模式下, 本配置無效。使用偽噪聲輸出時LFSR=0xAAA,MAMP2寄存器位可以屏蔽LFSR的某些位, 這時把本結構體成員賦值為DAC_LFSRUnmask_Bit0~DAC_LFSRUnmask_Bit11_0等宏即可;使用三角波輸出時,本結構體設置三角波的最大幅值, 可選擇為DAC_TriangleAmplitude_1~ DAC_TriangleAmplitude_4096等宏,見圖 DAC輸出三角波 , DAC在DHRx值的基礎上升,幅值達到MAMPx設置的最大幅度時下降,形成三角波的輸出。
(4) DAC_OutputBuffer
用于控制是否使能DAC的輸出緩沖(DAC_OutputBuffer_Enable/Disable), 使能了DAC的輸出緩沖后可以減小輸出阻抗,適合直接驅動一些外部負載。
代碼部分
void Dac1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;DAC_InitTypeDef DAC_InitType;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//使能DAC時鐘GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模擬輸入GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用觸發功能 TEN1=0DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形發生DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值設置DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ; //DAC1輸出緩存關閉 BOFF1=1DAC_Init(DAC_Channel_1,&DAC_InitType); //初始化DAC通道1DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC通道1DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12位右對齊數據格式設置DAC值 } //設置通道1輸出電壓 //vol:0~3300,代表0~3.3V void Dac1_Set_Vol(u16 vol) {double temp=vol;temp/=1000;temp=temp*4096/3.3;DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右對齊數據格式設置DAC值 } //部分main DAC_SetChannel1Data(DAC_Align_12b_R,dacval);//初始值為0 while(1){t++;key=KEY_Scan(0); if(key==WKUP_PRES){ if(dacval<4000)dacval+=200;DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//設置DAC值}else if(key==2) {if(dacval>200)dacval-=200;else dacval=0;DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//設置DAC值} if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定時時間到了{ adcx=DAC_GetDataOutputValue(DAC_Channel_1);//讀取前面設置DAC的值LCD_ShowxNum(94,150,adcx,4,16,0); //顯示DAC寄存器值temp=(float)adcx*(3.3/4096); //得到DAC電壓值adcx=temp;LCD_ShowxNum(94,170,temp,1,16,0); //顯示電壓值整數部分temp-=adcx;temp*=1000;LCD_ShowxNum(110,170,temp,3,16,0X80); //顯示電壓值的小數部分adcx=Get_Adc_Average(ADC_Channel_5,10); //得到ADC轉換值 temp=(float)adcx*(3.3/4096); //得到ADC電壓值adcx=temp;LCD_ShowxNum(94,190,temp,1,16,0); //顯示電壓值整數部分temp-=adcx;temp*=1000;LCD_ShowxNum(110,190,temp,3,16,0X80); //顯示電壓值的小數部分LED0=!LED0; t=0;} delay_ms(10); }總結
- 上一篇: win10下自动运行python程序脚本
- 下一篇: HCNP要复习多久?