极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 4706|回复: 7

OCROBOT ALPHA ESP8285 + LI POWER 电池电量监视器

[复制链接]
发表于 2018-4-29 23:01:34 | 显示全部楼层 |阅读模式

之前那个开箱帖做了很多的程序测试,看上比较凌乱。
这次单独发一帖整理一个使用 ESP8285 + ADS1015 + 锂电模块 的应用实例程序:电池电量监视器

TIM图片20180429220318.jpg

除了上面说那套OC开发板之外还需要一个台PC电脑,chrome浏览器65版,一个和PC联网的带WIFI功能路由器。
8285的主程序代码需要自行修改填上WIFI SSID和密码,8285的IP是自动获取的,要访问到监视器页面就需要知道IP地址,我是在路由查出来的。
监视器页面有一个gogogo的按钮,点击后就会开始记录电池电量变化,每隔10分钟刷新一次,同时绘制柱状图表
从满电开始到完全放电可能会超过10小时,如果电脑进入休眠,定时记录也会停止,所以最好把休眠禁止掉

这里是主程序代码
  1. //8285链接wifi路由 IP是动态获取的 至于怎么获得这个IP自己想办法 访问 http://x.x.x.x/read_adc_chart.htm 可见网页  
  2. //页面使用SPIFFS文件保存,页面定时异步更新当前所有adc数值,并且显示电量图表


  3. #include <ESP8266WiFi.h>
  4. #include <ESP8266WebServer.h>
  5. #include <FS.h>      //文件系统库SPIFFS

  6. #include <Wire.h>               //iic接口库
  7. #include <Adafruit_ADS1015.h>   //adc库,居然是出自Ada的

  8. const char *ssid = "你的WIFI";         //wifi ssid
  9. const char *password = "你的WIFI密码";     //wifi 密码

  10. Adafruit_ADS1015 ads;    //定义adc变量

  11. ESP8266WebServer server ( 80 );   //定义web服务

  12. void handleNotFound() {  //404页面
  13.   String message = "File Not Found\n\n";
  14.   message += "URI: ";
  15.   message += server.uri();
  16.   message += "\nMethod: ";
  17.   message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
  18.   message += "\nArguments: ";
  19.   message += server.args();
  20.   message += "\n";

  21.   for ( uint8_t i = 0; i < server.args(); i++ ) {
  22.     message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
  23.   }

  24.   server.send ( 404, "text/plain", message );  // 返回信息给浏览器(状态码,Content-type, 内容)
  25. }


  26. void ra_page() {  //读取adc数值页面
  27.   if(SPIFFS.exists("/read_adc_chart.htm")){  //如果文件存在
  28.     File file = SPIFFS.open("/read_adc_chart.htm", "r");              //打开文件
  29.     size_t sent = server.streamFile(file, "text/html");  //发送内容
  30.     file.close();          //关闭文件
  31.     return;
  32.   }
  33.   else
  34.   {
  35.     handleNotFound(); //404
  36.   }
  37. }

  38. void adc_values() {  //返回adc值
  39.   String p= "";
  40.   int adc;
  41.   unsigned long systime;

  42.   systime=millis();       //系统时间
  43.   p= String(systime);
  44.   
  45.   adc = ads.readADC_SingleEnded(0);   //获取各路adc的数值
  46.   p=p+","+String(adc);
  47.   adc = ads.readADC_SingleEnded(1);
  48.   p=p+","+String(adc);
  49.   adc = ads.readADC_SingleEnded(2);
  50.   p=p+","+String(adc);
  51.   adc = ads.readADC_SingleEnded(3);
  52.   p=p+","+String(adc);  

  53.   server.send(200, "text/plain", p);  //抛出返回信息  如果整个过程都没出错,应该返回这样的信息   系统运行毫秒数,0路电压,1路电压,2路电压,3路电压  所有数字之间均以逗号分隔
  54. }


  55. void setup() {
  56.   WiFi.begin ( ssid, password );  //wifi链接
  57.   delay(3500);
  58.   
  59.   SPIFFS.begin();  //这个文件系统实例好像在头文件里已经定义好了,无需声明直接开始工作吧

  60.   //web服务请求响应对象
  61.   server.on ( "/inline", []() {server.send ( 200, "text/plain", "this works as well" );} ); //这句意义重大:当主页面文件无法顺利上存时,至少能通过inline显示一个“好”页面
  62.   server.on ( "/read_adc_chart.htm", ra_page );
  63.   server.on ( "/adc", adc_values );
  64.   server.onNotFound ( handleNotFound );
  65.   server.begin();    //启动web服务

  66.   ads.begin();  //adc开始工作吧
  67. }

  68. void loop() {
  69.   server.handleClient();
  70. }



复制代码


由于这个程序是在Arduino 1.6.12 + Esp866 2.3.0版本下写的,上存程序和文件都需要手动把GPIO 0接地
如果想更加了解这个问题 请看这里 http://www.geek-workshop.com/thread-37411-1-1.html


接着是页面代码,页面文件的位置在主程序目录的data文件夹下


  1. <html>
  2.     <head>
  3.         <title>read adc values show chart</title>
  4.         <!--ESP8285 + ads1015-->
  5.         
  6.          <style>
  7.              canvas {
  8.                cursor: pointer;
  9.                border: 1px solid black;
  10.              }
  11.          </style>        
  12.         
  13.         <script type="text/javascript">
  14.         var ar_time = new Array();
  15.         var ar_volt = new Array();   
  16.             
  17.         function read_adc()  //get adc values
  18.         {
  19.             var url;
  20.             url ="/adc";

  21.             var xhr = new XMLHttpRequest();
  22.             xhr.open("GET", url, true);
  23.             xhr.onreadystatechange = function(e){
  24.             if (xhr.readyState == 4) {
  25.               var rtn = xhr.responseText;
  26.               document.getElementById("textarea").value+= rtn+"\n";   
  27.                
  28.               var ar_str = rtn.split(",");   
  29.               ar_time.push(ar_str[0]);   
  30.               ar_volt.push(ar_str[3]);   
  31.               }
  32.             };   

  33.             xhr.send();
  34.             draw_chart();
  35.         }
  36.             
  37.         function draw_chart() {

  38.         var canvas;
  39.         var context;

  40.         canvas = document.getElementById("canvas");
  41.         context = canvas.getContext("2d");        

  42.         context.clearRect(0, 0, canvas.width, canvas.height);  
  43.             
  44.         context.beginPath();         
  45.         context.lineWidth = 25;
  46.         context.strokeStyle = "#cd2828";   
  47.             
  48.         var i,v;
  49.         for (i = 0; i < ar_volt.length; i++) {
  50.           context.moveTo(65+i*25, 400);   
  51.           v=ar_volt[i];
  52.           context.lineTo(65+i*25, 1400-v);  
  53.             
  54.           context.save();
  55.           context.translate(65+i*25,410);
  56.           context.rotate(Math.PI / 2);         
  57.          
  58.           var n,h;
  59.           n=Math.floor(ar_time[i] / (1000*60) );
  60.           h=Math.floor(n / 60);
  61.           n= n % 60;   
  62.           context.fillText(h+" : "+n,0,0);
  63.          
  64.           var m=ar_volt[i]*0.003;     
  65.           context.fillText(m.toFixed(3)+'v',0,13);  
  66.             
  67.           context.restore();
  68.         }      
  69.         context.stroke();   
  70.         }
  71.                  

  72.         function button_gogogo() //btn_go make anything start once
  73.         {
  74.             document.getElementById("btn_go").disabled = true;
  75.             read_adc();
  76.             self.setInterval('read_adc()',600000);
  77.         }            
  78.         </script>  
  79.         
  80.     </head>
  81.     <body>
  82.         <textarea id="textarea" rows=5 cols=100></textarea>
  83.         <input id="btn_go" type="button" value="gogogo" onclick="button_gogogo()" />   
  84.         <div>
  85.         <canvas id="canvas" width="1300" height="500"></canvas>
  86.         </div>
  87.     </body>
  88. </html>   

复制代码

页面没写什么注释,因为整个文件会原原本本地上存到8285,就算注释也需要占用8285宝贵的存储空间,而且读取文件的速度也不怎么快。
其实注释也没什么用的,无论我怎么写也无法说清楚这个页面为什么只能在chrome下正常工作,而Internet Explorer则不行。
所以如果前端出了什么问题,一定就是浏览器的错

如果你想更加了解SPIFFS文件 请参阅这里 https://github.com/esp8266/arduino-esp8266fs-plugin

到目前为止我未能完完整整地玩一次从满电倒完全放电的测试,那么你想试试么?

回复

使用道具 举报

 楼主| 发表于 2018-4-29 23:17:59 | 显示全部楼层

由于我手上那块8285的丝印并没有很清晰地标出ADC信息,所以这里补充说明一下接线
ADC2要接上18650的正极,就是下图那个绿圈

回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-2 21:40:28 | 显示全部楼层

今日测试了8个小时,情况如下

20180502_8H.png

回复 支持 反对

使用道具 举报

发表于 2018-5-3 08:34:27 | 显示全部楼层
wing 发表于 2018-5-2 21:40
今日测试了8个小时,情况如下

还是挺耗电的。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-5 13:09:59 | 显示全部楼层
本帖最后由 wing 于 2018-5-5 13:38 编辑

终于完成了一次从满电到终止放电的过程了,历时超过15小时

20180505_15H.png

图表改进了,蓝色顺眼些吧,而且看起来不那么梯级了
每50秒获取一次电压,然后绘制宽度为1像素的柱状图,其实就是一条线,这样看起来比较平滑
每12次取值绘制下面的文字,也就是每隔10分钟有一次文字记录

主程序还是一样,下面是改进后的页面代码

  1. <html>
  2.     <head>
  3.         <title>battery chart</title>
  4.         <!--ESP8285 + ads1015-->
  5.         
  6.          <style>
  7.              canvas {
  8.                cursor: pointer;
  9.                border: 1px solid black;
  10.              }
  11.          </style>        
  12.         
  13.         <script type="text/javascript">
  14.         var ar_time = new Array();
  15.         var ar_volt = new Array();   
  16.             
  17.         function read_adc()  //get adc values
  18.         {
  19.             var url;
  20.             url ="/adc";

  21.             var xhr = new XMLHttpRequest();
  22.             xhr.open("GET", url, true);
  23.             xhr.onreadystatechange = function(e){
  24.             if (xhr.readyState == 4) {
  25.               var rtn = xhr.responseText;
  26.               document.getElementById("textarea").value+= rtn+"\n";   
  27.                
  28.               var ar_str = rtn.split(",");   
  29.               ar_time.push(ar_str[0]);   
  30.               ar_volt.push(ar_str[3]);   
  31.               }
  32.             };   

  33.             xhr.send();
  34.             draw_chart();
  35.         }
  36.             
  37.         function draw_chart() {

  38.         var canvas;
  39.         var context;

  40.         canvas = document.getElementById("canvas");
  41.         context = canvas.getContext("2d");        

  42.         context.clearRect(0, 0, canvas.width, canvas.height);  
  43.             
  44.         context.beginPath();         
  45.         context.lineWidth = 1;
  46.         context.strokeStyle = "#2828cd";   
  47.             
  48.         var i,v;
  49.         var vtime;   
  50.         for (i = 0; i < ar_volt.length; i++) {
  51.           context.moveTo(35+i, 650);   
  52.           v=ar_volt[i];
  53.           context.lineTo(35+i, 1400-v);  
  54.            
  55.           if (i % 12 ==0) {
  56.               context.save();
  57.               context.translate(35+i,660);
  58.               context.rotate(Math.PI / 2);         

  59.               var s,n,h;
  60.               s=Math.floor(ar_time[i] / 1000 );
  61.               n=Math.floor(s / 60 );
  62.               h=Math.floor(n / 60);
  63.               if (h<10){
  64.                 vtime='0'+h;
  65.               }else{
  66.                 vtime=h;         
  67.               }
  68.               n= n % 60;
  69.               if (n<10){
  70.                 vtime=vtime+' : 0'+n;  
  71.               }else{
  72.                 vtime=vtime+' : '+n;   
  73.               }
  74.               s= s % 60;
  75.               if (s<10){
  76.                 vtime=vtime+' : 0'+s;  
  77.               }else{
  78.                 vtime=vtime+' : '+s;   
  79.               }              
  80.               
  81.               var m=ar_volt[i]*0.003;     
  82.               context.fillText(m.toFixed(3)+'V '+vtime,0,0);  

  83.               context.restore();
  84.           }
  85.         }      
  86.         context.stroke();   
  87.         }
  88.                  

  89.         function button_gogogo() //btn_go make anything start once
  90.         {
  91.             document.getElementById("btn_go").disabled = true;
  92.             read_adc();
  93.             self.setInterval('read_adc()',50000);  //50s once
  94.         }            
  95.         </script>  
  96.         
  97.     </head>
  98.     <body>
  99.         <textarea id="textarea" rows=5 cols=100></textarea>
  100.         <input id="btn_go" type="button" value="gogogo" onclick="button_gogogo()" />   
  101.         <div>
  102.         <canvas id="canvas" width="1800" height="750"></canvas>
  103.         </div>
  104.     </body>
  105. </html>   
复制代码


整体来看分三段
从满电到3.7V,以一个基本相等的速度放电,这种状态维持6个多小时
3.7~3.4,以另一个基本相等的速度放电,这种状态维持8个小时
3.4之后就开始跳水了,一个小时不到就放尽了

来分析一下,最后10分钟的获取的电压数据

55806894,1010
55856890,1004
55906899,997
55956898,990
56006887,983
56056895,974
56106892,964
56156893,953
56206899,938
56256895,919
56306895,895
56356900,862

基本上就是到了3V就开始断崖式下跌,最后获取到的电压是 2.586V。
毅神说过保护电压大概在2.5左右,从实验数据来看基本吻合
回复 支持 反对

使用道具 举报

发表于 2018-6-28 09:16:22 | 显示全部楼层
有意思。。。按照理论推算,此电池标称容量为2AH,实际测试容量约为1.8~1.9Ah左右(5A负载), 理论容量为3.7X2=7.4Wh 。 ESP8285的待机功耗约为23ma,加上外设 ADC usb等 估计会有40-50ma的负载, 也就是说5x0.045=0.225W(取5V不取3.3V 因为板载使用的是线性稳压器,多余的能量是耗散掉的)
考虑升压器综合效率85%计算  7.4x0.85 = 6.29
6.29÷0.225 = 约为27小时  与实际测试值接近

误差主要来源就是wifi通讯时的发射功耗 会增加到200-300ma
回复 支持 反对

使用道具 举报

发表于 2018-6-28 09:17:59 | 显示全部楼层
根据实验数据,以后可以在理论值除以2的基础上推算wifi通讯情况下的实际耗电了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-9-28 12:02:20 | 显示全部楼层


测试一下,大家能不能看到下面的图

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-7-16 23:05 , Processed in 0.055742 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表