找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 36624|回复: 115
打印 上一主题 下一主题
收起左侧

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

  [复制链接]
楼主
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黑下载附件…………
复制代码
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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