STM32CubeMX學(xué)習(xí)筆記(20)——DAC接口使用(輸出正弦波)

一、DAC簡介

DAC(Digital-to-Analog Converter),即數(shù)字/模擬轉(zhuǎn)換模塊,故名思議,它的作用就是把輸入的數(shù)字編碼,轉(zhuǎn)換成對應(yīng)的模擬電壓輸出,它的功能與 ADC 相反。在常見的數(shù)字信號系統(tǒng)中,大部分傳感器信號被化成電壓信號,而 ADC 把電壓模擬信號轉(zhuǎn)換成易于計算機存儲、處理的數(shù)字編碼,由計算機處理完成后,再由 DAC 輸出電壓模擬信號,該電壓模擬信號常用來驅(qū)動某些執(zhí)行器件,使人類易于感知。如音頻信號的采集及還原就是這樣一個過程。

STM32 具有片上 DAC 外設(shè),它的分辨率可配置為 8 位或 12 位的數(shù)字輸入信號,具有兩個 DAC 輸出通道,這兩個通道互不影響,每個通道都可以使用 DMA 功能,都具有出錯檢測能力,可外部觸發(fā)。

二、DAC通道選擇

在 STM32 中具有 2 個這樣的 DAC 部件,每個 DAC 有 1 個對應(yīng)的輸出通道連接到特定的引腳,即:PA4-通道 1PA5-通道 2,為避免干擾,使用 DAC 功能時,DAC 通道引腳需要被配置成模擬輸入功能(AIN)。

三、新建工程

1. 打開 STM32CubeMX 軟件,點擊“新建工程”

2. 選擇 MCU 和封裝

3. 配置時鐘
RCC 設(shè)置,選擇 HSE(外部高速時鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)


選擇 Clock Configuration,配置系統(tǒng)時鐘 SYSCLK 為 72MHz
修改 HCLK 的值為 72 后,輸入回車,軟件會自動修改所有配置

4. 配置調(diào)試模式
非常重要的一步,否則會造成第一次燒錄程序后續(xù)無法識別調(diào)試器
SYS 設(shè)置,選擇 Debug 為 Serial Wire

四、DAC1

4.1 參數(shù)配置

Analog 中選擇 DAC 設(shè)置,并選擇 OUT1 Configuration 通道1


或者在右邊圖找到 PA4 引腳,選擇 DAC_OUT1

具體配置參數(shù)如下。

  • OUT1/2 Configuration
    對應(yīng)兩個輸出通道。
  • External Trigger
    外部中斷EXTI9 觸發(fā) 就是使用外部中斷來觸發(fā)DAC。
  • Output Buffer
    使能DAC輸出緩存。

DAC 集成了 2 個輸出緩存,可以用來減少輸出阻抗,無需外部運放即可直接驅(qū)動外部負(fù)載。每個 DAC 通道輸出緩存可以通過設(shè)置 DAC_CR 寄存器的 BOFFx 位來使能或者關(guān)閉。如果帶載能力還不行,后面就接一個電壓跟隨器,選擇運放一定要選擇電流大的型號。
使能輸出緩沖后,DAC 輸出的最小電壓為 0.2V,最大電壓為 VREF+-0.2,而未使能輸出緩沖則輸出可達(dá)到0V。

  • Trigger
    選擇DAC的觸發(fā)方式
    Timer 2/4/5/6/7/8 Trigger Out event 定時器觸發(fā),利用這種方式可以輸出特定的波形。在這里我們選擇定時器2。
    Software trigger 軟件觸發(fā),在本模式下,向 DAC_SWTRIGR 寄存器寫入配置即可觸發(fā)信號進行轉(zhuǎn)換。
  • Wave generation mode:Disable(不使用波形發(fā)生器)。

4.2 配置DMA

點擊 DMA Settings 添加 DAC_CH1 對應(yīng) DMA2 的通道3。DMA模式選擇循環(huán)模式,方向選為內(nèi)存到外設(shè)。

  • Priority
    當(dāng)發(fā)生多個 DMA 通道請求時,就意味著有先后響應(yīng)處理的順序問題,這個就由仲裁器也管理。仲裁器管理 DMA 通道請求分為兩個階段。第一階段屬于軟件階段,可以在 DMA_CCRx 寄存器中設(shè)置,有 4 個等級:非常高、高、中和低四個優(yōu)先級。第二階段屬于硬件階段,如果兩個或以上的 DMA 通道請求設(shè)置的優(yōu)先級一樣,則他們優(yōu)先級取決于通 道編號,編號越低優(yōu)先權(quán)越高,比如通道 0 高于通道 1。在大容量產(chǎn)品和互聯(lián)型產(chǎn)品中,DMA1 控制器擁有高于 DMA2 控制器的優(yōu)先級。
  • Mode
    Normal 表示單次傳輸,傳輸一次后終止傳輸。
    Circular 表示循環(huán)傳輸,傳輸完成后又重新開始繼續(xù)傳輸,不斷循環(huán)永不停止。
  • Increment Address
    Peripheral 表示外設(shè)地址自增。
    Memory 表示內(nèi)存地址自增。
  • Data Width
    Byte 一個字節(jié)。
    Half Word 半個字,等于兩字節(jié)。
    Word 一個字,等于四字節(jié)。

五、TIM2通用定時器

5.1 參數(shù)配置

Timers 中選擇 TIM2 設(shè)置,時鐘源 Clock Source 選擇內(nèi)部時鐘 Internal Clock

Parameter Settings 進行具體參數(shù)配置。

  • Prescaler(時鐘預(yù)分頻數(shù)):0 則驅(qū)動計數(shù)器的時鐘 CK_CNT = CK_INT(即72MHz)/(0+1) = 72MHz 即不分頻
  • Counter Mode(計數(shù)模式):Up(向上計數(shù)模式)
  • Counter Period(自動重裝載值):20-1
  • auto-reload-preload(自動重裝載):Disable(不使能)
  • TRGO Parameters(觸發(fā)輸出):Update Event(更新事件) 在定時器的定時時間到達(dá)的時候輸出一個信號(如:定時器更新產(chǎn)生TRGO信號來觸發(fā)ADC的同步轉(zhuǎn)換)

5.2 生成代碼

輸入項目名和項目路徑


選擇應(yīng)用的 IDE 開發(fā)環(huán)境 MDK-ARM V5

每個外設(shè)生成獨立的 ’.c/.h’ 文件
不勾:所有初始化代碼都生成在 main.c
勾選:初始化代碼生成在對應(yīng)的外設(shè)文件。 如 GPIO 初始化代碼生成在 gpio.c 中。

點擊 GENERATE CODE 生成代碼

六、庫函數(shù)

/* IO operation functions *****************************************************/
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef* hdac, uint32_t Channel);     //開啟DAC輸出
HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef* hdac, uint32_t Channel);   //關(guān)閉DAC輸出
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t* pData, uint32_t Length, uint32_t Alignment); //需要函數(shù)中不斷開啟   //開啟DAC的DMA輸出
HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel); //關(guān)閉DAC的DMA輸出
HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data);  //設(shè)置DAC輸出值
uint32_t HAL_DAC_GetValue(DAC_HandleTypeDef* hdac, uint32_t Channel);  //獲取DAC輸出值
/**
  * @brief  Starts the TIM Base generation.
  * @param  htim TIM Base handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim);

七、生成正弦波數(shù)據(jù)表

要輸出正弦波,實質(zhì)是要控制 DAC 以 v=sin(t)的正弦函數(shù)關(guān)系輸出電壓,其中 v 為電壓輸出,t 為時間。 而由于模擬信號連續(xù)而數(shù)字信號是離散的,所以使用 DAC 產(chǎn)生正弦波時,只能按一定時間間隔輸出正弦曲線上的點,在該時間段內(nèi)輸出相同的電壓值,若縮短時間間隔,提高單個周期內(nèi)的輸出點數(shù),可以得到逼近連續(xù)正弦波的圖形,見下圖 37-3,若在外部電路加上適當(dāng)?shù)碾娙轂V波,可得到更完美的圖形。



由于正弦曲線是周期函數(shù),所以只需要得到單個周期內(nèi)的數(shù)據(jù)后按周期重復(fù)即可,而單個周期內(nèi)取樣輸出的點數(shù)又是有限的,所以為了得到呈 v=sin(t)函數(shù)關(guān)系電壓值的數(shù)據(jù)通常不會實時計算獲取,而是預(yù)先計算好函數(shù)單個周期內(nèi)的電壓數(shù)據(jù)表,并且轉(zhuǎn)化成以 DAC 寄存器表示的值。 如 sin 函數(shù)值的范圍為[-1: +1],而 STM32 的 DAC 輸出電壓范圍為[0~3.3]V,按 12 位 DAC 分辨率表示的方法,可寫入寄存器的最大值為 212 = 4096,即范圍為[0:4096]。所以,實際輸出時,會進行如下處理:

  1. 抬升 sin 函數(shù)的輸出為正值:v = sin(t)+1 ,此時,v 的輸出范圍為[0:2];
  2. 擴展輸出至 DAC 的全電壓范圍: v = 3.3*(sin(t)+1)/2 ,此時,v 的輸出范圍為[0:3.3], 正是 DAC 的電壓輸出范圍,擴展至全電壓范圍可以充分利用 DAC 的分辨率;
  3. 把電壓值以 DAC 寄存器的形式表示:Reg_val = 212/3.3 * v = 211*(sin(t)+1),此時,存儲到 DAC 寄存器的值范圍為[0:4096];
  4. 實踐證明,在 sin(t)的單個周期內(nèi),取 32 個點進行電壓輸出已經(jīng)能較好地還原正弦波形,所以在 t∈[0:2π]區(qū)間內(nèi)等間距根據(jù)上述 Reg_val 公式運算得到 32 個寄存器值,即可得到正弦波表;
  5. 控制 DAC 輸出時,每隔一段相同的時間從上述正弦波表中取出一個新數(shù)據(jù)進行輸出,即可輸出正弦波。改變間隔時間的單位長度,可以改變正弦波曲線的周期。

生成的正弦波數(shù)據(jù)表:

[2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668, 3382, 3042, 2661, 
2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127, 310, 564, 878, 1240, 1636, 2048]

八、修改main函數(shù)

添加正弦波數(shù)據(jù)表

uint16_t Sine12bit[32] = {
    2048    , 2460  , 2856  , 3218  , 3532  , 3786  , 3969  , 4072  ,
    4093    , 4031  , 3887  , 3668  , 3382  , 3042  ,2661   , 2255  , 
    1841    , 1435  , 1054  , 714   , 428   , 209   , 65    , 3     ,
    24      , 127   , 310   , 564   , 878   , 1240  , 1636  , 2048
};

添加 HAL_TIM_Base_Start() 函數(shù),啟動定時器。
添加 HAL_DAC_Start_DMA()函數(shù),啟動 DAC 的 DMA 輸出。

uint16_t Sine12bit[32] = {
    2048    , 2460  , 2856  , 3218  , 3532  , 3786  , 3969  , 4072  ,
    4093    , 4031  , 3887  , 3668  , 3382  , 3042  ,2661   , 2255  , 
    1841    , 1435  , 1054  , 714   , 428   , 209   , 65    , 3     ,
    24      , 127   , 310   , 564   , 878   , 1240  , 1636  , 2048
};

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_DAC_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start(&htim2);
  HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)Sine12bit, 32, DAC_ALIGN_12B_R);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

九、實驗現(xiàn)象


112500 Hz 即 112.5KHz


十、注意事項

用戶代碼要加在 USER CODE BEGIN NUSER CODE END N 之間,否則下次使用 STM32CubeMX 重新生成代碼后,會被刪除。


? 由 Leung 寫于 2021 年 3 月 17 日

? 參考:STM32CubeMX系列教程8:數(shù)模轉(zhuǎn)換(DAC)
    《嵌入式-STM32開發(fā)指南》第二部分 基礎(chǔ)篇 - 第8章 模擬輸入輸出-DAC(HAL庫)
    STM32 CubeMX生成DAC+DMA+TIM生成正弦波

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容