单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
上一页
1/4
下一页
查看:38812|回复:120
打印上一主题下一主题

DIY毫安微安电流表(单片机10位ADC+LM358)程序原理图PCB及实物制作图片

 [复制链接]
跳转到指定楼层
楼主
ID:702386发表于 2020-12-24 17:36|只看该作者|只看大图回帖奖励
测试工程师一枚,实际工作中经常要测量产品的待机功耗和休眠功耗。通使用电流表来测产品的工作电流,突然萌生自己制作一个电流表的想法,然后学习了一下电流采样的原理,自己画了一个原理图,请同事帮忙画了PCB。程序方面借鉴了在51黑找到的一个测温度的例程。
基本设计:
单片机:使用 STC15W408AS,宽电压供电,8通道10位ADC,选择了SOP28封装引脚够用
电源:内置9V电池供电,使用LM1117-3.3V稳压芯片
检流电阻:毫安档使用1欧姆2512贴片电阻,微安档使用100欧姆2512贴片电阻。因考虑到产品实际待机工作电流(小于30mA)和休眠工作电流(小于100uA)。检流电阻的大小和精度可能在某些场合不合适,但已可以满足本项目需求。
运算放大器:使用LM358DR组成两路差分放大电路,分别放大毫安档和微安档检流电阻两端电压,放大倍数分别设置为10倍和50倍。
显示屏:LCD1602 3.3V版

调试结果:
实测LM358有一定的零点漂移,在程序中减掉零点漂移量后,毫安档和微安档的电流精度和万用表对比,结果精度非常高。LM358输出电压会比Vcc低大约不到1.5V,这一点一开始没有想到,这个会影响最大测量范围以及最大可测量点附近的精度。实际调试后,将量程确定为毫安档0-200mA和微安档0-400uA,已足够工作中的测试使用。如果要调整量程,只要调整检流电阻或者运放的放大倍数即可。

附件中有电路原理图和PCB及程序。比较基础的应用,分享给大家,希望可以给有需要的朋友带来帮助。
Altium Designer画的毫安微安电流表原理图和PCB图如下:(51hei附件中可下载工程文件)




制作出来的成品实物图如下:




微安档精度:


毫安档精度:





全部资料51hei下载地址:
程序.rar(38.04 KB, 下载次数: 852)
原理图和PCB.rar(10.88 MB, 下载次数: 970)

评分

黑币 +141
收起理由
+ 6
很给力!
+ 18
共享资料的黑币奖励!
+ 5
程序书写工整、清晰!适合下载学习。
+ 7
共享资料的黑币奖励!
+ 5
+ 100
共享资料的黑币奖励!

查看全部评分

来自 2#
ID:702386发表于 2020-12-26 17:08|只看该作者

新增NTC测温功能和秒表功能,采样和显示刷新周期由定时器控制。
NTC用的是P1.0口,因为电流采样很精确,所以没有使用基准电压源,把U2/R2/C5/C6/C7全拆掉,R2位置焊上10K 3435的NTC,C7位置焊上10K 1%的0603电阻。
效果好的很。

毫安微安电流表程序V2.1 增加NTC测温和秒表.rar

51.74 KB, 下载次数: 408, 下载积分: 黑币 -5

升级程序

评分

黑币 +30
收起理由
+ 30
回帖助人的奖励!

查看全部评分

板凳
ID:328014发表于 2020-12-24 20:10|只看该作者
太棒了,我一直想制作一个.下面是楼主的程序:
  1. /***************************************/
  2. /*     基于STC15W408AS的电流表设计     */
  3. /*     测量范围0-200mA,0-400uA       */
  4. /*     创建者 :zsw               */
  5. /*     创建时间:2020/12/21         */
  6. /***************************************/
  7. //2.5V基准电压接P1.0,uA采样接P1.1,mA采样接P1.2
  8. //毫安档使用1欧(5%)检流电阻,微安档使用100欧(1%)检流电阻。

  9. #include "STC15W408AS.H"
  10. #include "intrins.h"

  11. #define ADC_POWER   0x80   //ADC电源控制位
  12. #define ADC_FLAG   0x10   //ADC完成标志位
  13. #define ADC_START   0x08   //ADC启动控制位
  14. #define ADC_SPEED0   0x00   //ADC转换速度,一次转换需要540个时钟
  15. #define ADC_SPEED1   0x20   //ADC转换速度,一次转换需要360个时钟
  16. #define ADC_SPEED2   0x40   //ADC转换速度,一次转换需要180个时钟
  17. #define ADC_SPEED3   0x60   //ADC转换速度,一次转换需要90个时钟

  18. #define N 8   //ADC采样使用递推平均滤波算法,采样次数

  19. sbit lcdrs=P3^2;   //LCD1602指令和数据寄存器选择,高电平时为数据,低电平选择命令
  20. sbit lcdrw=P3^3;   //LCD1602读写选择,高电平为读,低电平为写
  21. sbit lcden=P3^4;   //LCD1602使能
  22. unsigned char Show[3]={0,0,0};   //显示数组mA
  23. unsigned char Show1[3]={0,0,0};   //显示数组uA
  24. unsigned int  ADC_Buf[N+1];       //采样数组mA
  25. unsigned int  ADC_Buf2[N+1];   //采样数值uA
  26. unsigned int current=0;         //采样毫安值
  27. unsigned int current2=0;       //采样微安值
  28. unsigned char num,ADCcount=0,ADCcount2=0;   //ADC采样次数变量
  29. unsigned char code table1[]="CURRENT1:";
  30. unsigned char code table2[]="CURRENT2:";

  31. /******************************
  32. 函数说明:延时函数,执行一次1毫秒,STC_ISP软件给出 @6MHz 1T单片机
  33. 入口参数:ms=延时毫秒数
  34. 出口参数:无
  35. ******************************/
  36. void Delay_MS(unsigned int ms)
  37. {
  38.    unsigned char i, j;
  39.    while(ms--)
  40.    {
  41.        i = 6;   j = 211;
  42.        do{
  43.          while (--j);
  44.        } while (--i);
  45.    }
  46. }

  47. /******************************
  48. 函数说明:LCD1602驱动
  49. ******************************/
  50. void write_com(unsigned char com)
  51. {
  52.    lcdrs=0;       //rs低电平为写命令
  53.    P2=com;        
  54.    Delay_MS(5);
  55.    lcden=1;       //EN先置高电平
  56.    Delay_MS(5);
  57.    lcden=0;       //短暂延时后EN置低电平
  58. }
  59. void write_dat(unsigned char dat)
  60. {
  61.    lcdrs=1;       //rs高电平为写数据
  62.    P2=dat;
  63.    Delay_MS(5);
  64.    lcden=1;
  65.    Delay_MS(5);
  66.    lcden=0;
  67. }
  68. /******************************
  69. 函数说明:初始化ADC寄存器
  70. ******************************/
  71. void Init_ADC(void)
  72. {
  73.    P1M1 |= 0x01;
  74.    P1M0& = ~1;         //设P1.0为高阻输入。因3.3V电源很精确,暂未使用2.5V基准电压源。
  75.    P1ASF = 0x06;       //打开P1.2和P1.1口的ADC功能
  76.    ADC_RES = 0;  
  77.    ADC_RESL= 0;       //清掉ADC转换结果寄存器
  78.    ADC_CONTR = ADC_POWER | ADC_SPEED3;   //使能A/D供电,设置转换速度90T
  79. }

  80. /******************************
  81. 函数说明:LCD1602初始化
  82. ******************************/
  83. void LCD1602_Init(void)
  84. {
  85.    lcdrw=0;
  86.    lcden=0;
  87.    P2=0;
  88.    write_com(0x38);   //设置显示模式为两行5*8显示
  89.    write_com(0x0C);   //初始化,开显示
  90.    write_com(0x06);   //初始化,读写一个字符后地址指针自动加1
  91.    write_com(0x01);   //清屏
  92.    write_com(0x80);   //数据地址指针从0开始  
  93.    for(num=0;num<9;num++)         //第1行显示'CURRENT1:'
  94.        write_dat(table1[num]);  
  95.    write_com(0x80+0x40);   //数据地址指针从0开始
  96.    for(num=0;num<9;num++)         //第1行显示'CURRENT2:'
  97.        write_dat(table2[num]);
  98. }
  99. /******************************
  100. 函数说明:查询方式读取ADC转换结果
  101. 入口参数:ch  ADC采样通道
  102. 出口参数:int ADC_RES ADC转换结果
  103. ******************************/
  104. unsigned int Get_ADC_Result(unsigned char ch)
  105. {
  106.    unsigned int result;
  107.    ADC_RES = 0;  
  108.    ADC_RESL= 0;               //清掉ADC转换结果寄存器
  109.    ADC_CONTR =ADC_POWER|ADC_SPEED3|ch|ADC_START;//配置ADC,设置转换通道,启动转换
  110.    _nop_();   _nop_();
  111.    _nop_();   _nop_();         //等待设置ADC_POWER完毕
  112.    while (!(ADC_CONTR& ADC_FLAG));//读取转换完毕标志位ADC_FLAG
  113.    ADC_CONTR& = ~ADC_FLAG;       //清除ADC_FLAG标志位
  114.    result = ADC_RES<<2|ADC_RESL;   //读取10位转换结果保存到result
  115.    return result;             //返回ADC转换结果10位
  116. }
  117. /******************************
  118. 函数说明:获取mA值
  119. ******************************/
  120. void Get_Current1(void)
  121. {
  122.    unsigned char xx;
  123.    unsigned int sum,currentvalue;
  124.    sum = currentvalue =0;  
  125.    ADC_Buf[N]=Get_ADC_Result(2);   //将ADC转换结果放数组最高位
  126.    if( ++ADCcount< 8)       //采样初期不使用滤波算法
  127.    {  
  128.        for(xx=0;xx<N;xx++)   //准备滤波算法的数据
  129.        {
  130.          ADC_Buf[xx]=ADC_Buf[xx+1];//所有数据循环左移
  131.        }
  132.        currentvalue=ADC_Buf[N];//采样初期使用当前采样值
  133.    }
  134.    else     //只有采样次数大于8次以后才使用滤波算法  
  135.    {
  136.        ADCcount=8;   //采样次数超过8次后,固定设置为8
  137.        for(xx=0;xx<N;xx++)   //滤波算法
  138.        {
  139.          ADC_Buf[xx]=ADC_Buf[xx+1];//所有数据循环左移
  140.          sum+=ADC_Buf[xx];   //求和
  141.        }
  142.        currentvalue=sum/N;       //求平均值      
  143.    }  
  144.    currentvalue=currentvalue*0.3223; //ADC平均值转化成mA电流值
  145.    if(currentvalue>=2)
  146.        currentvalue=currentvalue-2;     //实测零点漂移了2~3mA
  147.    if(currentvalue<=3)               //显示门槛
  148.        currentvalue=0;
  149.    current=currentvalue;
  150. }
  151.                         
  152. /******************************
  153. 函数说明:显示mA值
  154. ******************************/
  155. void Display_mA(void)
  156. {
  157.    if(current<=200)
  158.    {
  159.        Show[0]=current%1000/100;       //电流值百位
  160.        Show[1]=current%100/10;   //电流值十位
  161.        Show[2]=current%10;       //电流值个位
  162.        write_com(0x80+0x0A);         //第1行第10个字符开始显示
  163.        if(Show[0]>0)              
  164.          write_dat(0x30+Show[0]);   //写电流值百位
  165.        else
  166.          write_dat(' ');
  167.        if((Show[0]==0)&&(Show[1]==0))
  168.          write_dat(' ');           //写电流值十位
  169.        else
  170.          write_dat(0x30+Show[1]);
  171.        write_dat(0x30+Show[2]);       //写电流值个位
  172.        write_dat(' ');
  173.        write_dat('m');
  174.        write_dat('A');
  175.    }
  176.    else                     //超量程显示"999"
  177.    {
  178.        write_com(0x80+0x0A);
  179.        write_dat('9');
  180.        write_dat('9');
  181.        write_dat('9');
  182.        write_dat(' ');
  183.        write_dat('m');
  184.        write_dat('A');  
  185.    }
  186. }

  187. /******************************
  188. 函数说明:获取uA值
  189. ******************************/
  190. void Get_Current2(void)
  191. {
  192.    unsigned char xx;
  193.    unsigned int sum,currentvalue;
  194.    sum = currentvalue =0;  
  195.    ADC_Buf2[N]=Get_ADC_Result(1);   //将ADC转换结果放数组最高位
  196.    if( ++ADCcount2< 8)       //采样初期不使用滤波算法
  197.    {  
  198.        for(xx=0;xx<N;xx++)   //准备滤波算法的数据
  199.        {
  200.          ADC_Buf2[xx]=ADC_Buf2[xx+1];//所有数据循环左移
  201.        }
  202.        currentvalue=ADC_Buf2[N];//采样初期使用当前采样值
  203.    }
  204.    else     //只有采样次数大于8次以后才使用滤波算法  
  205.    {
  206.        ADCcount2=8;   //采样次数超过8次后,固定设置为8
  207.        for(xx=0;xx<N;xx++)   //滤波算法
  208.        {
  209.          ADC_Buf2[xx]=ADC_Buf2[xx+1];//所有数据循环左移
  210.          sum+=ADC_Buf2[xx];   //求和
  211.        }
  212.        currentvalue=sum/N;       //求平均值      
  213.    }  
  214.    currentvalue=currentvalue*0.6445; //ADC平均值转化成uA电流值
  215.    if(currentvalue>=15)
  216.        currentvalue=currentvalue-15;     //实测零点漂移了15uA
  217.    if(currentvalue<=3)               //显示门槛
  218.        currentvalue=0;
  219.    current2=currentvalue;
  220. }

  221. /******************************
  222. 函数说明:显示uA值
  223. ******************************/
  224. void Display_uA(void)
  225. {
  226.    if(current2<=400)
  227.    {
  228.        Show1[0]=current2%1000/100;       //电流值百位
  229.        Show1[1]=current2%100/10;       //电流值十位
  230.        Show1[2]=current2%10;         //电流值个位
  231.        write_com(0x80+0x40+0x0A);         //第2行第10个字符开始显示
  232.        if(Show1[0]>0)              
  233.          write_dat(0x30+Show1[0]);   //写电流值百位
  234.        else
  235.          write_dat(' ');
  236.        if((Show1[0]==0)&&(Show1[1]==0))
  237.          write_dat(' ');           //写电流值十位
  238.        else
  239.          write_dat(0x30+Show1[1]);
  240.        write_dat(0x30+Show1[2]);       //写电流值个位
  241.        write_dat(' ');
  242.        write_dat('u');
  243.        write_dat('A');
  244.    }
  245.    else                     //超量程显示"999"
  246.    {
  247.        write_com(0x80+0x40+0x0A);
  248.        write_dat('9');
  249.        write_dat('9');
  250.        write_dat('9');
  251.        write_dat(' ');
  252.        write_dat('u');
  253.        write_dat('A');  
  254.    }
  255. }

  256. void main(void)
  257. {
  258.    Init_ADC();           //初始化ADC
  259.    LCD1602_Init();         //初始化LCD1602
  260.    while(1)
  261.    {      
  262.        for(num=0;num<8;num++)
  263.        {
  264.          Get_Current1();   //获取mA电流值
  265.          Get_Current2();   //获取uA电流值
  266. ……………………

  267. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
地板
ID:430774发表于 2020-12-24 21:17|只看该作者
R8和R13有什么作用,可以去掉的吧
5#
ID:739727发表于 2020-12-25 00:53|只看该作者
zx929747216 发表于 2020-12-24 21:17
R8和R13有什么作用,可以去掉的吧

提供运放差分输入偏置电流
6#
ID:687694发表于 2020-12-26 20:11|只看该作者
不用提供Avref 15w408内部有1.19V基准。
7#
ID:702386发表于 2020-12-26 22:07|只看该作者
lovexulu 发表于 2020-12-26 20:11
不用提供Avref 15w408内部有1.19V基准。

多谢指点!
8#
ID:64053发表于 2021-1-19 22:45|只看该作者
zsw3721 发表于 2020-12-26 17:08
新增NTC测温功能和秒表功能,采样和显示刷新周期由定时器控制。
NTC用的是P1.0口,因为电流采样很精确, ...

楼主你好,我的MCU是20P 脚的能帮改一下程序吗
9#
ID:702386发表于 2021-1-20 08:55|只看该作者
93mxt 发表于 2021-1-19 22:45
楼主你好,我的MCU是20P 脚的能帮改一下程序吗

也是STC15W408AS吗?20P的MCU,要调整一下IO口,建议LCD的数据口改到P3口,RS、RW、EN分别改到P1.3、P1.4、P1.5。建议你自己动手哟,这样才好玩。
10#
ID:276663发表于 2021-1-20 09:19|只看该作者
做的不错,具有实用价值的东西才是好东西!
11#
ID:235954发表于 2021-1-27 14:07|只看该作者
3D外壳想做来着、
12#
ID:390571发表于 2021-2-4 11:58|只看该作者
正需要这个,看着精度挺不错,下载学习,屏幕能小型化点便携就更好了
13#
ID:576203发表于 2021-2-6 22:22|只看该作者
下面那行挺空的,加个电压显示就完美了,这个比较实用。我是买的成品毫安和微安表改的。测试脉冲型负载就换成指针微安表,数码管的反应跟不上
14#
ID:632112发表于 2021-2-24 11:46|只看该作者

做的不错,下载学习,
15#
ID:799716发表于 2021-2-25 14:15|只看该作者
C程序小白入门 请教currentvalue=currentvalue*0.6445; //ADC平均值转化成uA电流值  这个0.6445如何的得来的
16#
ID:702386发表于 2021-2-25 15:50|只看该作者
18176214303 发表于 2021-2-25 14:15
C程序小白入门 请教currentvalue=currentvalue*0.6445; //ADC平均值转化成uA电流值  这个0.6445如何的得来 ...

10位ADC有1024个采样分辨值,采样获得的值ADC=Vadc * (1024/Vcc),连续采样8次获得ADC平均值先赋给currentvalue。
微安采样电阻100欧,运放放大50倍,则AD通道的采样电压为Vadc=I(A)*100欧*50=I(uA)*100*50/1000000,代入上式,可算得I(uA)=currentvalue*3.3*1000000/(1024*100*50)=currentvalue*0.6445.
17#
ID:799716发表于 2021-3-1 10:25|只看该作者
zsw3721 发表于 2021-2-25 15:50
10位ADC有1024个采样分辨值,采样获得的值ADC=Vadc * (1024/Vcc),连续采样8次获得ADC平均值先赋给curren ...

非常感谢 学习了
18#
ID:460466发表于 2021-3-1 12:40|只看该作者
液晶显示就不能用中文吗?!
19#
ID:582255发表于 2021-3-1 12:58|只看该作者
zsw3721 发表于 2020-12-26 17:08
新增NTC测温功能和秒表功能,采样和显示刷新周期由定时器控制。
NTC用的是P1.0口,因为电流采样很精确, ...

楼主能贴的元件清单不
20#
ID:799716发表于 2021-3-1 16:39|只看该作者
zsw3721 发表于 2021-2-25 15:50
10位ADC有1024个采样分辨值,采样获得的值ADC=Vadc * (1024/Vcc),连续采样8次获得ADC平均值先赋给curren ...

电路上,实际是51倍放大吧,计算按50计算
21#
ID:702386发表于 2021-3-1 21:42|只看该作者
18176214303 发表于 2021-3-1 16:39
电路上,实际是51倍放大吧,计算按50计算

微安档的运算放大器就是按50倍放大的,你可以看一下差分放大器的放大倍数计算公式。
22#
ID:799716发表于 2021-3-2 08:47|只看该作者
zsw3721 发表于 2021-3-1 21:42
微安档的运算放大器就是按50倍放大的,你可以看一下差分放大器的放大倍数计算公式。

嗯,学习了
23#
ID:796531发表于 2021-3-18 08:54|只看该作者
好东西,在制作一个 耐压测试仪正好用到参考
24#
ID:796531发表于 2021-3-18 09:43|只看该作者
建议在 100Ω电阻两端并联一个正向压降(Vf)低一点的肖特基二极管,如VS-10BQ015HM3(210mV @ 1A )上正下负 ,保证 设备待机突变为开机时 R5两端压降不影响设备工作

评分

黑币 +20
收起理由
+ 20
回帖助人的奖励!

查看全部评分

25#
ID:138956发表于 2021-3-18 09:48|只看该作者


做的不错,学习学习。
26#
ID:702386发表于 2021-3-18 14:23|只看该作者
paladina 发表于 2021-3-18 09:43
建议在 100Ω电阻两端并联一个正向压降(Vf)低一点的肖特基二极管,如VS-10BQ015HM3(210mV @ 1A )上正下 ...

不错的建议。谢谢。
27#
ID:856401发表于 2021-3-20 21:53|只看该作者
照着楼主的资料,做一个
28#
ID:92222发表于 2021-4-2 08:45|只看该作者
感谢分享,能出个数码管显示的版本就好了,这样成本低一点
29#
ID:430492发表于 2021-4-2 11:24|只看该作者
设计还是比较巧的,谢谢楼主无私分享!!
30#
ID:702386发表于 2021-4-2 20:37|只看该作者
c51流浪者 发表于 2021-4-2 08:45
感谢分享,能出个数码管显示的版本就好了,这样成本低一点

数码管的功耗太大,显示的内容又有限。这块LCD1602 3.3V的屏大概7块钱,也能接受吧。
31#
ID:66328发表于 2021-6-21 11:35|只看该作者
感谢楼主分享,楼主还可以看到这个帖子么,请教下,单片机烧录时选用多大的晶振频率?谢谢!
32#
ID:702386发表于 2021-6-21 21:34|只看该作者
hnqylgq 发表于 2021-6-21 11:35
感谢楼主分享,楼主还可以看到这个帖子么,请教下,单片机烧录时选用多大的晶振频率?谢谢!

选的内部6M的RC频率。
33#
ID:816540发表于 2021-6-24 10:32|只看该作者
谢谢分享!正在学习51单片机。
34#
ID:948569发表于 2021-7-3 08:55|只看该作者
楼主, 有没有测试过AD跳动几个码
35#
ID:702386发表于 2021-7-3 11:56|只看该作者
KinHimTang 发表于 2021-7-3 08:55
楼主, 有没有测试过AD跳动几个码

拿直流源接色环电阻,毫安和微安档测量值都很稳定,只波动1mA和1uA左右。
36#
ID:507641发表于 2021-7-22 03:22|只看该作者
学习下,如果用彩屏更炫耀,下来看看
37#
ID:507641发表于 2021-7-22 03:45|只看该作者
建议L358 VCC加R C滤波好的,
38#
ID:936913发表于 2021-7-22 22:42|只看该作者
本帖最后由 wjqzywmm 于 2021-7-24 11:49 编辑

感谢楼主分享,有个小疑问:Get_Current1()中adc结果为什么要循环左移呢?小于8直接给数组赋值应该也可以吧。
今天改造自己的程序,明白了循环左移的意义
39#
ID:27031发表于 2021-7-22 23:21|只看该作者
谢谢分享DIY毫安微安电流表
40#
ID:718536发表于 2021-8-2 16:21|只看该作者
kkk2020 发表于 2021-2-6 22:22
下面那行挺空的,加个电压显示就完美了,这个比较实用。我是买的成品毫安和微安表改的。测试脉冲型负载就换 ...

提高一下刷新速度就好很多了

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网