基於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
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...