一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 9323|回复: 26
收起左侧

[电池DIY] usart-GPU制作的1~6S锂电池电压彩屏显示器(含源代码)【正式推出】

[复制链接]
发表于 2014-12-9 21:10 | 显示全部楼层 |阅读模式
本帖最后由 apachectl 于 2014-12-9 23:22 编辑

玩航模的都知道对电池的保养非常重要,否则价值不菲的航模电池极容易鼓肚,这就离不开锂电池电压显示仪,这个得必要性和保养方法这里就不再累述了,玩航模的都知道。

      现在市面上的显示器,大多数是由数码管构成的,最大的不方便之处就是显示信息量太小,只能一个一个的将信息分时显示出来,非常不直观,因此我们制作了这个使用高分彩屏的电压显示器;
IMG_0911.JPG

在电路设计上,我们采用了带4key的Usart-GPU,串口液晶屏,其电路和 http://item.taobao.com/item.htm?id=41696639973

这款串口屏完全一样,只是考虑到便携性,采用了一块非常不常见的2.0吋320X240的液晶屏(平常的2.0吋是220X176分辨率的),这种高分屏显示的效果非常细腻;

单片机上,我们采用的是STM32的单片机,这种单片机使用的是12位AD,且是32位单片机,在AD采样上带DMA传输,速度和精度都有保障;

下面谈谈显示仪的精度问题:

    查查某宝上的同类产品,大多数产品使用的非stm32的单片机,有用STM8的,有用AVR的,这类单片机的AD都是10位的,也就是说分辨率是1024级,当检测6S 24V(实际应该更高)的时候,分辨率是24V/1024=0.024V,按照惯例,AD有+-3LSB的误差范围,也就是说,直接测量会在0.072V之间跳动,如果考虑到某节电池是2个电压相减得到,那么极端误差可能到0.144V(上一节电池-3LSB,这一节电池+3LSB,当然,这种极端情况较少出现),什么0.01V的精度,都是扯淡;能保证0.1V的精度就不错了;

   对于我们的产品,在精度方面也是同样的,只是采用了12位AD,因此分辨率是4096级,按照上面的计算,24V/3096=0.006V,3LSB误差0.018V,也就是说单独测量最高6S勉强达到0.01V精度,电池电压相减,极端误差0.036V;另外,在分压网络的选择上,低电压,比如1S那个,选择了6V满量程,2S选择10.7V满量程,这样在常用的3S上精度可以更高;

测量3S电池的情况:

IMG_0923.JPG


本程序全部开源,因此很多界面以及功能都是可以修改的,比如,电池电压与电量的百分比:

// 0 10 20 30 40 50 60 70 80 90 100
uc16 Liqx[11]={300,350,368,373,377,381,385,390,395,408,419};

可以自行修改;
IMG_0908.JPG

在主板的布局上,左边是GPU电路,用于控制液晶屏的显示,右边是CPU电路,用于采样电池电压,其实单片机的还有很多管脚没有使用,但是都引出了,因此此板实际上还可以当单片机的核心板使用;电阻分压网络实际做到了8S,但是考虑到用户较少,因此产品只设计的6S;

由于管脚都引出了,因此可以通过MOS管控制蜂鸣器,可以根据每节电池的电压,控制放电通路MOS的关断等等,让这块板子很容易升级制作成放电仪之类的东西;

在使用上,下侧排插,左边为GND,右边分别为1S 2S 3S.......将锂电池插上既可以显示;4个按钮目前只有左下角一个按钮有用,其他3个按钮留作以后扩展使用;在接电状态,按下左下角按钮,就可以进入debug界面,显示测量的AD值;

IMG_0913.JPG

IMG_0918.JPG
100mhz给设计的简单外壳:
IMG_0934.JPG

截止到12月16日前,凡是购买备注“一乐账号”的,优惠10元(壳子不单卖),拍下改价


断开跳线,本产品可以当一个4key的串口屏使用,可以当stm32f030f4p6的核心板,开发板使用,也是一个串口屏不错的评估板;
淘宝链接:http://item.taobao.com/item.htm?id=42843185420
 楼主| 发表于 2014-12-9 21:10 | 显示全部楼层
本帖最后由 apachectl 于 2014-12-9 21:27 编辑

源代码工程文件下载:

源代码工程文件包:http://pan.baidu.com/s/1i3029Qd
gpumaker资源文件包:http://pan.baidu.com/s/1eQ7uuKa
编译好的CPU文件:http://pan.baidu.com/s/1Cmk26
淘宝链接:http://item.taobao.com/item.htm?id=42843185420
  1. //=============================================================================
  2. //文件名称:main.c
  3. //功能概要:key
  4. //版权所有:apachectl
  5. //淘宝网店:http://shop104540872.taobao.com/
  6. //版本更新:2014-04-12
  7. //=============================================================================

  8. //头文件
  9. #include "stm32f0xx.h"
  10. #include "stdio.h"
  11. #include "def.c"
  12. #include "init.c"
  13. #include "func.c"

  14. u8 isKeyDown(void);        //检测是否有按键按下
  15. void u232out(char * buf1);
  16. void setup(void);
  17. void loop(void);
  18. void onkey(void);
  19. void showwin1(void);
  20. void showdebug(void);
  21. //=============================================================================
  22. //文件名称:main
  23. //功能概要:主函数
  24. //参数说明:无
  25. //函数返回:int
  26. //=============================================================================

  27. void gowin(u8 n)
  28. {        winnum=n;
  29.         setup();
  30. }

  31. int main(void)
  32. {       
  33.         system_init();
  34.         USART_ENABLE_REV();
  35.         Delayms(2000000);
  36.         LoadROM();
  37.         GpuSend("DR2;CLS(0);SPG(1);\r\n");
  38.         winnum=1;

  39.         cjs=0;
  40.         iscmd=0;
  41.         iscmdok=0;
  42.         loopcount=0;
  43.         iswaiting=0;
  44.         setup();
  45.        
  46.         while(1)
  47.         {               
  48.                 if (iscmdok==1) {onkey();iscmdok=0;};
  49.                
  50.                 loopcount++;
  51.                 if (loopcount==100000)
  52.                 {        if (iswaiting==0) loop();
  53.                         loopcount=0;
  54.                 }
  55.                
  56.         }
  57. }


  58. void setup(void)
  59. {        switch (winnum)
  60.         {        case 1:       
  61.                         GpuSend("DR2;CLS(0);DS24(4,0,'锂电池电压',1);DS24(160,0,'总电压:',4);BOX(0,30,319,130,11);\r\n");
  62.                         break;
  63.                 case 2:       
  64.                         GpuSend("DR2;CLS(0);SPG(2);\r\n");
  65.                         break;
  66.                 case 3:       
  67.                         GpuSend("DR2;CLS(0);DS16(0,0,'Debug:',1);\r\n");
  68.                         break;
  69.         }
  70.         Delayms(200000);
  71. }


  72. void loop(void)
  73. {        switch(winnum)
  74.         {                case 1:
  75.                                 showwin1();
  76.                                 break;
  77.                         case 3:
  78.                                 showdebug();
  79.                                 break;
  80.         }
  81. }


  82. void onkey(void)
  83. {                //BC:0001   BA:0001  BB:0000
  84.        
  85.         switch (winnum)
  86.         {        case 1:
  87.                         if ((cmd[0]=='B') &(cmd[1]=='C') &(cmd[6]=='1'))
  88.                         {        //A按键单击
  89.                                 gowin(3);
  90.                         }
  91.                         if ((cmd[0]=='B') &(cmd[1]=='A') &(cmd[6]=='1'))
  92.                         {        //A按键长按击
  93.                                 gowin(2);
  94.                                 iswaiting=1;        //进入按钮释放等待循环中
  95.                                
  96.                         }
  97.                         if ((cmd[0]=='B') &(cmd[1]=='B'))
  98.                         {        iswaiting=0;        //长按按键释放
  99.                         }
  100.                         break;
  101.                 case 2:
  102.                         if ((cmd[0]=='B') &(cmd[1]=='C') &(cmd[6]=='1'))
  103.                         {        //A按键单击
  104.                                         Set5VBase();
  105.                                         SaveROM();
  106.                                         gowin(1);
  107.                         }
  108.                         break;
  109.                 case 3:
  110.                         if ((cmd[0]=='B') &(cmd[1]=='C') &(cmd[6]=='1'))
  111.                         {        //A按键单击
  112.                                         gowin(1);
  113.                         }
  114.                         break;

  115.                

  116.         }
  117.         //if(cmd[0]==
  118. }


  119. void showwin1(void)
  120. {                u8 i,y,c;
  121.                 u16 x1,x2;
  122.                 CompADC();
  123.                 CompVol();
  124.                 CompLi();
  125.                 CompCellPer();
  126.                 min=99;max=0;argv=0;
  127.                 js=0;
  128.                 for (i=0;i<6;i++)
  129.                 {        if (Li[i]>1)
  130.                         {        argv+=Li[i];
  131.                                 js++;       
  132.                                 if (Li[i]<=min) min=Li[i];
  133.                                 if (Li[i]>max) max=Li[i];
  134.                         }
  135.                 }
  136.                 if (min==99) min=0;
  137.                 argv=argv/js;
  138.                 for (i=0;i<6;i++)
  139.                 {        x1=i*54+10;x2=x1+30;
  140.                         if (Li[i]>1)
  141.                         {        sprintf(buf,"ICON(%d,165,1,11,1,%d);DS16(%d,224,'%.2f',4);",54*i,CellPer[i],54*i+4,Li[i]);
  142.                                 GpuSend(buf);
  143.                                 y=(Li[i]-argv)*100;
  144.                                 y=80-y;
  145.                                 c=2;
  146.                                 if (y>130) {y=130;c=1;};
  147.                                 if (y<30) {y=30;c=1;};
  148.                                 sprintf(buf,"BOXF(%d,31,%d,%d,0);BOXF(%d,%d,%d,129,%d);",x1,x2,y,x1,y,x2,c);
  149.                                 GpuSend(buf);
  150.                         }
  151.                         else
  152.                         {        sprintf(buf,"ICON(%d,165,1,11,1,10);DS16(%d,224,' --- ',4);BOXF(%d,31,%d,79,0);BOXF(%d,81,%d,129,0);",54*i,54*i+4,x1,x2,x1,x2);
  153.                                 GpuSend(buf);
  154.                                
  155.                         }
  156.                 }
  157.                 sprintf(buf,"DS24(240,0,'%.2fV',4);DS16(10,140,'最高:%.2fV   平均:%.2fV   最低:%.2fV',3);",LV[js-1],max,argv,min);
  158.                 GpuSend(buf);
  159.                 GpuSend("PL(0,80,320,80,11);\r\n");
  160.                 Delayms(1000000);
  161. }


  162. void showdebug(void)
  163. {        u8 i;
  164.         CompADC();
  165.         CompVol();
  166.         for (i=0;i<M;i++)
  167.         {        sprintf(buf,"DS16(10,%d,'AD%d:%5d',4);",i*20+20,i,After_filter[i]);
  168.                 GpuSend(buf);
  169.         }
  170.         for (i=0;i<6;i++)
  171.         {        sprintf(buf,"DS16(100,%d,'V%d:%.2fV',15);",i*20+40,i,LV[i]);
  172.                 GpuSend(buf);
  173.         }
  174.        
  175.         GpuSend("\r\n");
  176. }



  177. /*****END OF FILE****/
复制代码
上面是主程序代码,这里的看点是,串口屏处理按键形成的主消息处理体的模型,可以从结构上看出,把所有的窗体显示都编上号,这样就可以很方便的进行各个界面的消息处理以及界面切换,很容易编写复杂界面的软件,再多界面也不怕!

大家可以研究下示例中的复杂界面是如何显示和刷新的,这点很重要
再则是如何构建一个消息循环的多页面体系




发表于 2014-12-9 21:20 | 显示全部楼层
顶上
发表于 2014-12-9 21:30 | 显示全部楼层
这个是经常玩航模的人所需要的
发表于 2014-12-9 21:36 | 显示全部楼层
不错
发表于 2014-12-9 21:37 | 显示全部楼层
不错!
发表于 2014-12-9 21:38 | 显示全部楼层
这个玩航模的真的可以看看,谁要是有能力可以改成一个自动的放电仪,对放电进行控制  
 楼主| 发表于 2014-12-9 21:43 | 显示全部楼层
tgl97141155 发表于 2014-12-9 21:38
这个玩航模的真的可以看看,谁要是有能力可以改成一个自动的放电仪,对放电进行控制

理论上把一个IO口,控制MOS,电池接一个黄金电阻,放电到预设电值,断开MOS,这个不是很复杂
开源的就这点好,很容易加上这个功能
发表于 2014-12-9 22:12 | 显示全部楼层
另外好像没说可以防反接电池接错接反不烧件
发表于 2014-12-9 22:45 | 显示全部楼层
做得很漂亮.但是单从航模方面考虑还是有一些不足.

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-3-29 01:35 , Processed in 0.072072 second(s), 51 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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