基於STM32的外部電源電壓檢測

来源:https://www.cnblogs.com/XAUT-HuziGe/archive/2022/07/27/15151773.html
-Advertisement-
Play Games

STM32測量外部電源的電壓 本人在項目中遇到一個需求:使用電池給STM32開發板供電,並需要實時顯示當前電源的電量情況。這個需求可以說是很常見了,但是卻困擾了我整整一個多月。 在收到這個需求的時候我首先想到的就是上網查找相關的技術貼,其中一條名為《基於STM32F103內部AD測量電池電壓》的帖子 ...


STM32測量外部電源的電壓

本人在項目中遇到一個需求:使用電池給STM32開發板供電,並需要實時顯示當前電源的電量情況。這個需求可以說是很常見了,但是卻困擾了我整整一個多月。

在收到這個需求的時候我首先想到的就是上網查找相關的技術貼,其中一條名為《基於STM32F103內部AD測量電池電壓》的帖子花費了我大量的時間,最後沒能完成測試,偶然的一次嘗試我發現了一個新電路

 

圖中的電阻可以自行調整,R1和R2電阻的作用是分壓,對所測電壓進行縮小處理:

   測量所得電壓=R2/(R2+R1)×電源電壓  

根據該公式可以推出

   電源電壓=(R2+R1)/R2×測量所得電壓  

R0、R3和R4是對電路起到保護作用的電阻,阻值也可以適當調整。

我在實驗中使用了兩個相同的電路組合測試兩個電壓,導致相互之間有影響

 

電路中實測阻值為

R0

213

R5

32.1K

R1

213

R6

19.7K

R2

9.85K

R7

32.1K

R3

8.66K

R8

19.3K

R4

19.7K

R9

8.63K

使用穩壓電源測試得到數據併進行擬合得到GPIO口的數值與實際電壓的關係:

 

所以得到電壓的計算公式:

   電壓=數值/4096×2.3583×3.3   

然後根據電路以及該公式,對電池從滿電一直到放電結束進行數據採集和分析:

 

採集了近萬條數據,擬合出了電壓-時間關係以及電量電壓關係。

最後運行在開發板上如圖:

 

測試代碼:

  1 /************************************************
  2  功能:基於STM32單片機正點原子精英板的電池電量檢測
  3  輸入:特定電路位置的電壓值  5  開發者:XAUT—餘濤
  6  版本:1.0
  7  最後更新時間:2020/08/16
  8 
  9 ************************************************/
 10 
 11 //初始化GPIO口
 12 void Electricity_Init(void)
 13 {
 14     GPIO_InitTypeDef GPIO_InitStructure;
 15     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA時鐘
 16     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5 anolog輸入     金屬感測器
 17     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //模擬輸入引腳
 18     GPIO_Init(GPIOA, &GPIO_InitStructure);
 19     Adc2_Init();
 20 }
 21 //求冪的函數
 22 double mypow(float x, int y) {
 23     double res = 1;
 24     int i;
 25     for(i = 0; i < y; i++)
 26     {
 27         res *= x;
 28     }
 29     return res;
 30 }
 31 
 32 int main(void)
 33 {
 34     char writeTemp_val[10];  //用於存儲resault轉為字元後的值
 35     char ElectricityVal[60] = ""; //用於保存電量數據
 36     float voltage = 0; //定義電壓變數
 37     int Electricity = 0;   //定義電量數值
 38     int value = 0;
 39     double ElectricityVOL = 0; //電量餘量
 40     float temporary = 0; //臨時變數
 41     int i = 0;
 42     int time = 0; //可工作時長
 43     FIL fil, newfil;          //文件指針指向打開的文件
 44     FRESULT fileRes;       //文件打開結果
 45     UINT bww = 32;           //寫入文件數據類型
 46     u32 total, free;         //記憶體SD卡的總容量和剩餘容量
 47     u8 res = 0;        //扇區格式化結果
 48     vu8 key = 0;       //定義key接收按鍵信號
 49     usmart_dev.init(SystemCoreClock / 1000000);    //初始化USMART
 50     delay_init();                                                                //延時函數初始化
 51     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                         //設置中斷優先順序分組為組2:2位搶占優先順序,2位響應優先順序
 52     uart_init(115200);                                                           //串口初始化為115200,串口監視顯示時,波特率應當設為115200
 53     LED_Init();                                                                      //初始化與LED連接的硬體介面
 54     LCD_Init();                                                                      //初始化LCD
 55     BEEP_Init();             //初始化蜂鳴器埠
 56     KEY_Init();           //初始化與按鍵連接的硬體介面
 57     Electricity_Init();       //初始化GPIO口
 58     W25QXX_Init();                //初始化W25Q128
 59     RTC_Init();                  //RTC初始化
 60     usmart_dev.init(72);        //初始化USMART
 61     my_mem_init(SRAMIN);        //初始化內部記憶體池
 62     exfuns_init();                            //為fatfs相關變數申請記憶體
 63     f_mount(fs[0], "0:", 1);                     //掛載SD卡
 64     res = f_mount(fs[1], "1:", 1);                 //掛載FLASH.
 65 
 66     POINT_COLOR = RED;                                                      //設置字體為紅色
 67     //顯示提示信息
 68     LCD_ShowString(30, 50, 200, 16, 16, "Elite STM32");
 69     LCD_ShowString(30, 70, 200, 16, 16, "Shell Firing Simulation");
 70     LCD_ShowString(30, 110, 200, 16, 16, "ATOM@ALIENTEK");
 71     LCD_ShowString(30, 110, 200, 16, 16, "2021/5/04");
 72     POINT_COLOR = BLUE;                                                     //設置字體為藍色
 73     LCD_ShowString(30, 130, 200, 16, 16, "Number of launches: 0");            //已發射炮彈實際數量
 74     LCD_ShowString(30, 110, 200, 16, 16, "System is initializing!");            //系統已經準備就緒
 75     LCD_ShowString(30, 150, 200, 16, 16, "Launched: 0");                      //檢測到炮彈發射信號次數
 76     LCD_ShowString(30, 170, 200, 16, 16, "Filled in: 0");                     //檢測到炮彈裝填信號次數
 77     LCD_Clear(WHITE);//清屏
 78     while(font_init())             //檢查字型檔
 79     {
 80         while(SD_Init())//檢測不到SD卡
 81         {
 82             LCD_ShowString(30, 110, 200, 16, 16, "SD Card Error!");
 83             delay_ms(500);
 84             LCD_ShowString(30, 110, 200, 16, 16, "Please Check! ");
 85             delay_ms(500);
 86             LED0 = !LED0; //DS0閃爍
 87         }
 88         LCD_ShowString(30, 70, 110, 16, 16, "SD Card OK");
 89         LCD_ShowString(30, 110, 130, 16, 16, "Font Updating...");
 90         key = update_font(20, 110, 16, "0:"); //更新字型檔
 91         while(key)//更新失敗
 92         {
 93             LCD_ShowString(30, 110, 110, 16, 16, "Font Update Failed!");
 94             delay_ms(200);
 95             LCD_Fill(20, 110, 130, 110 + 16, WHITE);
 96             delay_ms(200);
 97         }
 98         LCD_ShowString(30, 110, 110, 16, 16, "Font Update Success!   ");
 99         delay_ms(100);
100         LCD_Clear(WHITE);//清屏
101     }
102     POINT_COLOR = RED;             //設置字體為紅色
103     Show_Str(30, 50, 200, 16,  "電量檢測測試代碼", 16, 0);
104     Show_Str(30, 70, 200, 16,  "XAUT-HuziGe", 16, 0);
105     POINT_COLOR = BLUE;                                                     //設置字體為藍色
106     Show_Str(30, 110, 200, 16, "系統正在載入!", 16, 0);          //系統已經準備就緒
107     Show_Str(30, 130, 200, 16, "電量檢測數值: 0", 16, 0);                   //檢測到串口數值
108     Show_Str(30, 150, 200, 16, "電池電壓: 0.000V", 16, 0);                   //根據數值轉換的電壓
109     Show_Str(30, 170, 200, 16, "剩餘電量:  0 %", 16, 0);                   //根據電壓得到的電量
110     Show_Str(30, 190, 200, 16, "預計還能工作: 0 h", 16, 0);                   //根據電量計算工作時間
111     Disp_Time(30, 90, 16);  //顯示時間
112     //delay_ms(100);
113     // RTC_Set(2021,8,16,9,41,0);//設置時間
114 
115     if(res == 0X0D) //FLASH磁碟,FAT文件系統錯誤,重新格式化FLASH
116     {
117         Show_Str(30, 110, 200, 16, "格式化FLASH...", 16, 0);;    //格式化FLASH
118         res = f_mkfs("1:", 1, 4096); //格式化FLASH,1,盤符;1,不需要引導區,8個扇區為1個簇
119         if(res == 0)
120         {
121             f_setlabel((const TCHAR *)"1:ALIENTEK");    //設置Flash磁碟的名字為:ALIENTEK
122             Show_Str(30, 110, 200, 16, "格式化完成!", 16, 0);    //格式化完成
123         } else Show_Str(30, 110, 200, 16, "格式化失敗!", 16, 0);    //格式化失敗
124         delay_ms(1000);
125     }
126     LCD_Fill(30, 110, 240, 110 + 16, WHITE);        //清除顯示
127     while(exf_getfree("0", &total, &free))    //得到SD卡的總容量和剩餘容量
128     {
129         Show_Str(30, 110, 200, 16, "FATFS文件系統載入失敗!", 16, 0);
130         delay_ms(200);
131         LED0 = !LED0; //DS0閃爍
132     }
133     POINT_COLOR = BLUE; //設置字體為藍色
134     Show_Str(30, 110, 200, 16, "文件系統載入完成!       ", 16, 0);
135     delay_ms(1000);
136     fileRes = f_open(&fil, "0:/Electricity.txt", FA_OPEN_ALWAYS | FA_WRITE); //打開文件Electricity.txt,若沒有則新建
137     while(FR_OK != fileRes)      //打開文件Electricity.txt,若沒有則新建,檢查文件打開是否成功
138     {
139         Show_Str(30, 110, 200, 16, "文件打開失敗!", 16, 0);
140         delay_ms(500);
141         Show_Str(30, 110, 200, 16, "正在重試!    ", 16, 0);
142         delay_ms(500);
143         LED0 = !LED0; //DS0閃爍
144         fileRes = f_open(&fil, "0:/Electricity.txt", FA_OPEN_ALWAYS | FA_WRITE); //打開文件Electricity.txt,若沒有則新建
145         LCD_ShowxNum(30 , 2110, fileRes, 3, 16, 0);    //顯示錯誤類型
146     }
147     f_lseek(&fil, fil.fsize);   //指針指到文件末尾
148     Show_Str(30, 110, 200, 16, "文件一打開測試完成!", 16, 0);
149     while(FR_OK != f_close(&fil)) {}
150     delay_ms(1000);
151     fileRes = f_open(&newfil, "0:/Metal.txt", FA_OPEN_ALWAYS | FA_WRITE); //打開文件Metal.txt,若沒有則新建
152     while(FR_OK != fileRes)      //打開文件Metal.txt,若沒有則新建,檢查文件打開是否成功
153     {
154         Show_Str(30, 110, 200, 16, "文件打開失敗!", 16, 0);
155         delay_ms(500);
156         Show_Str(30, 110, 200, 16, "正在重試!    ", 16, 0);
157         delay_ms(500);
158         LED0 = !LED0; //DS0閃爍
159         fileRes = f_open(&newfil, "0:/Metal.txt", FA_OPEN_ALWAYS | FA_WRITE); //打開文件Metal.txt,若沒有則新建
160         LCD_ShowxNum(30 , 2110, fileRes, 3, 16, 0);    //顯示錯誤類型
161     }
162     f_lseek(&newfil, newfil.fsize);   //指針指到文件末尾
163     Show_Str(30, 110, 200, 16, "文件二打開測試完成!", 16, 0);
164     delay_ms(1000);
165     while(FR_OK != f_close(&newfil)) {}
166     Show_Str(30, 110, 200, 16, "系統準備就緒!             ", 16, 0);        //系統已經準備就緒
167     while(1)
168     {
169         Disp_Time(30, 90, 16);  //顯示時間
170         //連續讀取10次取平均值
171         for(i = 0; i < 10; i++)
172         {
173             printf("in for");
174             Electricity = Get_Adc2(ADC_Channel_6);    //讀取ADC值通道6  即PA6
175             value += Electricity;
176             delay_ms(10);
177         }
178         Electricity = value / 10;
179         value = 0;
180         strcpy(ElectricityVal, Res_Time());    //將時間寫入字元串  Res_Time()函數是作為自己寫的,獲得當前時間組成的字元串
183         voltage = (float)(Electricity * (2.3583 * 3.3 / 4096) - 1.6494); //計算電壓值(新電路測電源)
184         sprintf(writeTemp_val, "\t%4d\t%.3f\n", Electricity, voltage);
185         strcat(ElectricityVal, writeTemp_val);
186         temporary = voltage;
187         ElectricityVOL = ((-285.53) * mypow(voltage, 6) + 5601.4 * mypow(voltage, 5) - 45377 * mypow(voltage, 4) + 194353 * mypow(voltage, 3) - 464275 * mypow(voltage, 2) + 586596 * mypow(voltage, 1) - 306296);
188         if(ElectricityVOL > 1)
189             time = ElectricityVOL / 100 * 32; //滿電情況下測試可連續工作32小時
190         else
191             time = 0;
192 
193         LCD_ShowxNum(30 + 10 * 8, 170, ElectricityVOL, 3, 16, 0);
194         LCD_ShowxNum(30 + 14 * 8, 190, time, 2, 16, 0);
195         voltage = temporary;
196         //顯示電壓到LCD屏幕上
197         LCD_ShowxNum(30 + 14 * 8, 130, Electricity, 4, 16, 0);
198         Electricity = voltage;
199         voltage -= Electricity;
200         voltage *= 1000;
201         voltage += 10000;
202         LCD_ShowxNum(30 + 10 * 8, 150, Electricity, 1, 16, 0);//整數部分
203         LCD_ShowxNum(30 + 12 * 8, 150, voltage, 3, 16, 0);//小數部分
204 
205         //打開文件Electricity.txt,若沒有則新建
206         while(FR_OK != f_open(&fil, "0:/Electricity.txt", FA_OPEN_ALWAYS | FA_WRITE)) {};
207         f_lseek(&fil, f_size(&fil));   //指針指到文件末尾
208         f_write(&fil, ElectricityVal, strlen(ElectricityVal), &bww);   //寫入讀取到的值到Electricity.txt
209         while(FR_OK != f_close(&fil)) {}
210         //每10秒進行一次檢測並記錄
211         for(i = 0; i < 10; i++)
212         {
213             delay_ms(1000);
214         }
215         //delay_ms(1000 * 60 * 5); //延時時間為10ms,可以檢測按鍵按下的最佳延時
216     }
217 }

 

本文來自博客園,作者:愛抖腿的虎子哥,轉載請註明原文鏈接:https://www.cnblogs.com/XAUT-HuziGe/p/15151773.html

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

-Advertisement-
Play Games
更多相關文章
  • 所在單位有消息推送的需求,整理了一下,具體要求如下: 伺服器(ASP.NET)往桌面客戶端(WPF)單向推送; 客戶端消費消息分為一次性消費(如:掃面支付結果推送)、多次消費(如:訂單推送) ClientId線上狀態其他客戶端不能再用相同的ClientId連接 一開始使用了SingalR,缺點如下: ...
  • 分享如何使用WPF 製作 Windows 屏保 WPF 製作 Windows 屏保 作者:驚鏵 原文鏈接:https://github.com/yanjinhuagood/ScreenSaver 框架使用.NET452; Visual Studio 2019; 項目使用 MIT 開源許可協議; 更多 ...
  • ## 前言 在很多的場合我都遇到過一些群友提這樣的一些問題: 為什麼Java有GC調優而CLR沒有聽說過有GC調優呢? 到底是Java的JVM GC比較強還是C#使用的.NET CLR的GC比較強呢? 其實業內已經有幾位大佬的高贊文章和大家分享一下,主要討論JVM和CLR還有GC調優,今天就借用大 ...
  • 寫在前面 本系列的文章是博主邊學邊記錄的,可能不是特別的正確,因為會加上博主自己的理解,僅供參考。 正文 一、文件的物理組織方式 目前常用的外存組織方式有: 1.連續組織方式 為每個文件分配一篇連續的磁碟空間,稱為連續組織方式。 2.鏈接組織方式 在對文件採取鏈式組織方式時,可以為每個文件分配不連續 ...
  • 1. CentOS 7系統開機時選擇預設第一啟動項,按字母"e"鍵編輯啟動項;如圖1所示 圖1 2. 使用鍵盤上下左右方向鍵,往下找到 linux16 開頭的一行,定位到 ro (read only);如圖2所示 圖2 3. 編輯 ro 為 rw (read write),併在其後寫入 init=/ ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 前言 本環境通過使用VMware在Ubuntu20.04下通過VScode搭建docker環境,可通過遠程連接容器進行開發。(僅作參考) 一、環境準備 VMware 15 pro,Ubuntu20.04,VScode(Linux版本) 虛擬機搭建 ...
  • 寫在前面 本系列的文章是博主邊學邊記錄的,可能不是特別的正確,因為會加上博主自己的理解,僅供參考。 正文: 1.文件目錄 文件目錄是一種數據結構,用於標識系統中文件及其物理地址,供檢索的時候使用。對於目錄的管理有如下要求: 1.實現按名存取 2.提高對目錄的檢索速度 3.文件共用 在多用戶系統中,應 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 項目部署 之前我們講解Linux操作系統時,就提到,我們服務端開發工程師學習Linux系統的目的就是將來我們開發的項目絕大部分情況下都需要部署在Linux系統中。那麼在本章節,我們將通過兩種方式,來演示項目部署,分別是:手動部署項目 和 基於sh ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...