18-CubeMx+Keil+Proteus模擬STM32 - DAC

来源:https://www.cnblogs.com/sheepeach/archive/2022/05/31/STM32F103_DAC.html
-Advertisement-
Play Games

本文例子參考《STM32單片機開發實例——基於Proteus虛擬模擬與HAL/LL庫》 源代碼:https://github.com/LanLinnet/STM33F103R6 項目要求 在SPI匯流排通信的基礎上,使用單片機控制DAC晶元MCP4921以1秒為周期輸出正弦波,正弦波的波動範圍為0-3 ...


本文例子參考《STM32單片機開發實例——基於Proteus虛擬模擬與HAL/LL庫》
源代碼:https://github.com/LanLinnet/STM33F103R6

項目要求

在SPI匯流排通信的基礎上,使用單片機控制DAC晶元MCP4921以1秒為周期輸出正弦波,正弦波的波動範圍為0-3.3V。

硬體設計

  1. 第一節的基礎上,在Proteus中添加電路如下圖所示。其中我們添加了一個DAC晶元MCP4921

    此外,我們還添加了兩個虛擬儀錶:一個示波器OSCILLOSCOPE和一個SPI匯流排調試工具SPI DEBUGGER

  2. MCP4921:
    1)簡介:STM32F103R6單片機本身不自帶DAC,如果設計到數模轉換的項目,可以選擇DAC晶元MCP4921。MCP4921是美國Microchip公司的串列12位DAC晶元,相容SPI,最高通信頻率為20MHz,一次轉換時間為4.5μs,工作電壓為2.7-5.5V。
    2)引腳:MCP4921引腳的功能如下表所示。

    3)通信數據格式:MCP4921只有數據輸入,沒有數據輸出,單片機只需要將16位數據(12位數字量和4位配置信息)一起打包發給DAC晶元,DAC隨即開始數模轉換過程。MCP4921通信數據格式如下表所示。

    • \(\overline A/B\)位:對於MCP4921,由於只有A通道,所以該位只能選0。
    • BUF位:參考電壓\(V_{REF}\)輸入緩衝器控制位,設1時緩衝,設0時未緩衝。
    • \(\overline{GA}\)位:輸出增益選擇位,設1時無增益,設0時兩倍增益。
    • \(\overline{SHDN}\)位:待機模式設置為,設1時不進入待機模式,設0時進入待機模式。
  3. 正弦波形的生成:
    1)存在問題:MCP4921是12位DAC晶元,因此輸入數字量的範圍是0x000-0x3FF,輸出模擬量電壓範圍為0-\(V_{REF}\),即無法輸出負電壓,那麼就無法輸出完整的正弦波形。
    2)解決方案:

    • 通過外圍元器件搭建調理電路使電路能夠輸出負電壓。
    • 將正弦波信號沿縱軸(電壓/數字量)正向移動,確保波谷也位於橫軸(時間)的上方。

    3)採樣表:這裡我們選擇後一個方案,可以推出正弦波計算公式為
    \(D=512\times\sin\left(2\pi\;t\right)+512\)
    為了提高單片機CPU的執行效率,這裡我們使用查表法。在1秒內,每隔0.02秒計算一次採樣值,其採樣表如下表所示。

  4. 打開CubeMX,建立工程。STM32F103R6單片機自帶一個SPI模塊,但是為了便於移植,本項目中採用GPIO引腳模擬SPI時序。設置PA4、PA5、PA7均為GPIO_Output點擊“Categories”中的“GPIO”,修改GPIO各參數如下圖所示。有關SPI通信部分可以參考第17節

  5. 點擊“Generator Code”生成Keil工程。

軟體編寫

  1. 考慮到代碼的可移植性,這裡將SPI和MCP4921的驅動代碼全部封裝成函數並分別歸入頭文件“vSPI.h”和“MCP4921.h”中。我們可以先在...\Core\Src文件夾中建立這兩個頭文件,此時Keil可能找不到對應文件,可以直接將文件拽入Keil中進行編輯,然後再在“main.c”文件中進行include。

  2. 點擊“Open Project”在Keil中打開工程,打開“vSPI.h”,添加代碼如下。

    #ifndef INC_VSPI_H_
    #define INC_VSPI_H_
    
    #include "main.h"
    
    //軟體延時函數,單位為微秒
    void delay_us(uint16_t n)
    {
      uint16_t i = n * 8;
      while(i--);
    }
    
    //SPI匯流排使能
    void vSPI_En()
    {
      HAL_GPIO_WritePin(GPIOA, vnCS_Pin, GPIO_PIN_RESET);
      HAL_GPIO_WritePin(GPIOA, vSCK_Pin, GPIO_PIN_RESET);
      delay_us(4);
    }
    
    //SPI匯流排禁止
    void vSPI_Dis()
    {
      HAL_GPIO_WritePin(GPIOA, vSCK_Pin, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOA, vnCS_Pin, GPIO_PIN_SET);
    }
    
    //SPI主站發送1位元組
    void vSPI_SndByte(uint8_t dat)		//dat表示發送的位元組
    {
      uint8_t i;
      for(i=0; i<8; i++)
      {
        HAL_GPIO_WritePin(GPIOA, vSCK_Pin, GPIO_PIN_RESET);
        delay_us(4);
        if(dat & 0x80)
        {
          HAL_GPIO_WritePin(GPIOA, vMOSI_Pin, GPIO_PIN_SET);
        }
        else 
          HAL_GPIO_WritePin(GPIOA, vMOSI_Pin, GPIO_PIN_RESET);
        dat<<=1;
        //上升沿
        HAL_GPIO_WritePin(GPIOA, vSCK_Pin, GPIO_PIN_SET);
        delay_us(4);
      }
    }
    
    #endif /* INC_VSPI_H_ */
    

    打開“MCP4921.h”,添加代碼如下。

    #ifndef INC_MCP4921_H_
    #define INC_MCP4921_H_
    
    #include "main.h"
    #include "vSPI.h"
    
    //寫入MCP4921: Cmd-指令(僅高4位)  Dat-數據(12位)
    void MCP4921Write(uint8_t Cmd, uint16_t Dat)
    {
      uint8_t DatM, DatL;		//數據高位元組、低位元組
      DatL = (uint8_t)(Dat & 0x00ff);	
      DatM = (uint8_t)((Dat>>8) & 0x00ff);
      vSPI_En();		//SPI匯流排使能
      vSPI_SndByte(0x70|DatM);		//先寫高位元組
      vSPI_SndByte(DatL);		//再寫低位元組
      vSPI_Dis();		//SPI匯流排禁止
    }
    #endif /* INC_MCP4921_H_ */
    
  3. 隨後我們需要在main.c文件中的最前面引入我們自定義的頭文件

    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "vSPI.h"		//引入自定義頭文件
    #include "MCP4921.h"
    /* USER CODE END Includes */
    

    在全局中定義正弦波輸出的表

    /* USER CODE BEGIN PV */
    //查表法
    static uint16_t tD[50] = 
    {
    	512, 576, 639, 700, 759, 813, 862, 907, 944, 975,
    	999, 1015, 1023, 1023, 1015, 999, 975, 944, 907, 862,
    	813, 759, 700, 639, 576, 512, 448, 385, 324, 265, 
    	211, 162, 117, 80, 49, 25, 9, 1, 1, 9,
    	25, 49, 80, 117, 162, 211, 265, 324, 385, 448
    };
    /* USER CODE END PV */
    

    最後,在main函數中定義迴圈變數,並調用我們自定義的函數每隔20ms計算一次採樣值並輸出

    /* USER CODE BEGIN 1 */
    int i;		//迴圈變數i
    /* USER CODE END 1 */
    
    /* USER CODE BEGIN WHILE */
    while (1)
    {
      for(i=0; i<50; i++)
      {
        MCP4921Write(0x70, tD[i]);
        HAL_Delay(20);		//每隔20ns計算(輸出)1次採樣值
      }
    /* USER CODE END WHILE */
    
    /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
    

聯合調試

  1. 點擊運行,生成HEX文件。
  2. 在Proteus中載入相應HEX文件,點擊運行。可以看到示波器中顯示的波形為正弦波(註意示波器的調整)。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 校園失物招領網站 | lijinghai 項目介紹 📖 👉基於Springboot+vue+uni-app的校園失物招領平臺. 含平臺主體PC端、微信小程式和web後臺數據管理平臺. 失物招領信息一覽 信息發佈(支持圖片上傳) 項目技術棧 ⭐ PC端(WarmSearch-PC):Vue 2.0 ...
  • 最新博客更新見我的個人主頁: https://xzajyjs.cn 我們在使用Django構建網站時常需要對接第三方支付平臺的支付介面,這裡就以支付寶為例(其他平臺大同小異),使用支付寶開放平臺的沙箱環境進行實驗。 我們這裡使用一個第三方的AliPay Python SDK(github) 下麵看一 ...
  • 項目開發中遇到的一個問題,c++ 虐我千萬遍,我待 c++ 如初戀… ...
  • .NET5升級.NET6 Ant Design Pro V5 IdentityServer4實戰 前後端分離 oidc-client-ts .NET6部署Linux雲服務 功能變數名稱 ...
  • 一、簡介 單點登錄(SingleSignOn,SSO) 指的是在多個應用系統中,只需登錄一次,就可以訪問其他相互信任的應用系統。 JWT Json Web Token,這裡不詳細描述,簡單說是一種認證機制。 OAuth2.0 OAuth2.0是一個認證流程,一共有四種方式,這裡用的是最常用的授權碼方 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 一、Docker介紹 ​ 我們知道,一臺物理機需要運行多個程式,然而每個程式又需要各自不同的一堆依賴,所有程式全裝上的話,整個物理機系統會變得混亂不堪,同時也容易出問題,使得我們後續維護比較困難。而如果利用docker,就可以直接下載一個鏡像,投 ...
  • 問題 之前一直有夜晚睡覺前電腦💻關機的習慣,主要是想著電腦也跟人一樣♨️要休息😂。然後最近想著自己 Mac 乾脆每天睡眠💤算了,省得每天開關機麻煩,所以就最近這段時間每次夜晚睡覺前主動去點了電腦的 「Sleep」電源選項。然而事情並不簡單,由於我有看日誌的習慣,所以每天早起的時候看了一下電源歷 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...