找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5567|回复: 5
收起左侧

基于PIC16F877单片机的简易数字电压表设计及proteus仿真

  [复制链接]
ID:697394 发表于 2020-6-9 18:50 | 显示全部楼层 |阅读模式
与各位分享我的代码
1.系统功能
1.1可测0~5V的8路输入电压值;
1.2在LED数码管上轮流显示;
1.3单路选择显示;
2.系统硬件设计
2.1 单片机采用PIC16F877
2.2 键盘为4×4行列式键盘,按键设有10个数字键0……9,和5个功能键依次是:各通道轮流显示键、单通道显示键、向左滚动显示键、显示启动/停止键、回车键。
2.3有3位LED管,左边1位用于指示显示通道,右边2位显示电压值,保留到小数点后面1位。
3系统软件设计
3.1键盘管理程序(包括键扫描、键处理程序);
3.2LED动态显示程序;
3.3各通道轮流显示,共显示8个通道,每通道显示1s;
3.4 单通道显示,仅显示指定通道电压,并保持到其他功能键按下。

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
@82KKR_003[IEK%OUJ${FSA.png

单片机源程序如下:
  1. //作者:云树阿云
  2. #include <htc.h>
  3. #include <pic.h>
  4. #define uchar unsigned char
  5. #define uint unsigned int
  6. __CONFIG(0x3b32);//状态字
  7. uchar table[]={0x00,0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//数码管显示字符表
  8. uchar channel[]={0x41,0x49,0x51,0x59,0x61,0x69,0x71,0x79};//代表8个通道被按下的状态表
  9. uchar key_num;//按键标志位
  10. uchar disp_num;//通道标志位
  11. uchar left_num;
  12. uchar loop_num;
  13. uint volval=0;//电压值
  14. uint enter=0;//回车被按下标志位
  15. uint on_off=0;//开机标志位
  16. uint loop_disp=0;//循环显示标志位
  17. uint single_disp=0;//单通道显示标志位
  18. uint left_move=0;//左移显示标志位
  19. uint a;//用于显示的换算位
  20. uint b;//用于显示的换算位
  21. uint c;//用于显示的换算位
  22. uint d;//用于左移显示的转移中间值
  23. uchar e=2;
  24. uchar onkey_num;



  25. void delay(uint x)//延时程序
  26. {uint times,num;
  27.    for(times=x;times>0;times--)
  28.       for(num=110;num>0;num--);
  29. }

  30. void display(uint i,uint j)//显示程序
  31.    {
  32.      a=i/10;//通过电压值和通道值算出需要显示的值
  33.      b=i-a*10;//通过电压值和通道值算出需要显示的值
  34.     a=a+10;//为电压第一位加上小数点
  35.       c=j;
  36.       if(enter==0)
  37.       {a=-1;
  38.          b=-1;
  39.          //c=-1;
  40.          }
  41.     TRISD=0x00;//设置输出端口
  42.     TRISB=0x00;//设置输出端口
  43.       delay(1);//延时
  44.          RB0=0;//选择需要亮起的数码管
  45.          RB1=1;
  46.          RB2=1;         
  47.         PORTD=table[c+1];//输出需要显示的数字
  48.        delay(1);//延时
  49.          RB0=1;//选择需要亮起的数码管
  50.          RB1=0;
  51.          RB2=1;   
  52.       PORTD=table[a+1];
  53.          delay(1);//延时
  54.          RB0=1;//选择需要亮起的数码管
  55.          RB1=1;
  56.          RB2=0;         
  57.          PORTD=table[b+1];//输出需要显示的数字
  58.       }

  59. void getab(uint i,uint j)//左移显示时获得当前的a,b,c值
  60. { a=i/10;
  61.    b=i-a*10;
  62.    a=a+10;
  63.    c=j;
  64.    }  

  65. void leftdisplay()//左移显示模式的显示程序,类似显示程序
  66.    {
  67.     TRISD=0x00;
  68.     TRISB=0x00;
  69.       delay(1);
  70.          RB0=0;
  71.          RB1=1;
  72.          RB2=1;         
  73.         PORTD=table[c+1];
  74.        delay(1);
  75.          RB0=1;
  76.          RB1=0;
  77.          RB2=1;   
  78.       PORTD=table[a+1];
  79.          delay(1);
  80.          RB0=1;
  81.          RB1=1;
  82.          RB2=0;         
  83.          PORTD=table[b+1];
  84.       }      
  85.       
  86. void leftmove()//实现左移显示的程序(交换abc)
  87.       
  88.    {        if(left_num==8)
  89.       {
  90.          left_num=0;
  91.       ADCON0=channel[0];
  92.         uint adval;
  93.         GO=1;
  94.         while(GO)
  95.         adval=ADRESH;
  96.         adval=adval<<8|ADRESL;
  97.         volval=adval/20;        
  98.          a=-1;
  99.         b=volval/10;
  100.         b=b+10;
  101.         c=left_num;
  102.       }
  103.       else{
  104.          //disp_num++;
  105.         ADCON0=channel[left_num];
  106.          
  107.         uint adval;
  108.         GO=1;
  109.         while(GO)
  110.         adval=ADRESH;
  111.         adval=adval<<8|ADRESL;
  112.         volval=adval/20;        
  113.          a=-1;
  114.         b=volval/10;
  115.         b=b+10;
  116.         c=left_num;
  117.      }
  118.       }
  119. void scan()//扫描程序获得key_num
  120.       {        TRISC=0xf0;//C端口高四位输出,低四位输入
  121.          PORTC=0xfe;//首先扫描第一列
  122.          key_num=PORTC;//读取C端口低四位,获得key_num
  123.          key_num=key_num&0xf0;//判断低四位是否有1存在
  124.          if (key_num!=0xf0)//如果低四位有1(第一行有键被按下)
  125.          { delay(10);//去抖动
  126.          key_num=PORTC;//重新读取
  127.          key_num=key_num&0xf0;//得到低四位中为1的位,其他位置0
  128.             if (key_num!=0xf0)
  129.             {
  130.                key_num=key_num|0x0e;//加上高四位中被扫描的值,获得代表被按下键的值:key_num
  131.                }
  132.             }
  133.           else//其他列依次判断
  134.           {
  135.              PORTC=0xfd;
  136.          key_num=PORTC;
  137.          key_num=key_num&0xf0;
  138.          if (key_num!=0xf0)
  139.          { delay(10);
  140.          key_num=PORTC;
  141.          key_num=key_num&0xf0;
  142.             if (key_num!=0xf0)
  143.             {
  144.                key_num=key_num|0x0d;
  145.                }
  146.             }
  147.             else
  148.             {
  149.              PORTC=0xfb;
  150.          key_num=PORTC;
  151.          key_num=key_num&0xf0;
  152.          if (key_num!=0xf0)
  153.          { delay(10);
  154.          key_num=PORTC;
  155.          key_num=key_num&0xf0;
  156.             if (key_num!=0xf0)
  157.             {
  158.                key_num=key_num|0x0b;
  159.                }
  160.             }
  161.             else
  162.             {
  163.              PORTC=0xf7;
  164.          key_num=PORTC;
  165.          key_num=key_num&0xf0;
  166.          if (key_num!=0xf0)
  167.          { delay(10);
  168.          key_num=PORTC;
  169.          key_num=key_num&0xf0;
  170.             if (key_num!=0xf0)
  171.             {
  172.                key_num=key_num|0x07;
  173.                }
  174.             }
  175.                }
  176.                }
  177.              }
  178.          }
  179. void switched()//根据key_num改变相应标志位
  180.          {
  181.             switch(key_num)
  182.                {case 0xee:disp_num=7;enter=0;break;//通道选择
  183.                 case 0xed:disp_num=4;enter=0;break;//通道选择
  184.                 case 0xeb:disp_num=1;enter=0;break;//通道选择
  185.                 case 0xe7:if(onkey_num!=key_num){on_off=!on_off;enter=0;}break;
  186.                            //on_off=1;                          break;//开机
  187.                 //case 0xde:disp_num=7;enter=0;break;//通道选择
  188.                 case 0xdd:disp_num=5;enter=0;break;//通道选择
  189.                   case 0xdb:disp_num=2;enter=0;break;//通道选择
  190.                 case 0xd7:disp_num=0;enter=0;break;//通道选择
  191.                 //case 0xbe:disp_num=7;enter=0;break;//通道选择
  192.                 case 0xbd:disp_num=6;enter=0;break;//通道选择
  193.                 case 0xbb:disp_num=3;enter=0;break;//通道选择
  194.                 case 0xb7:enter=1;break;//回车键
  195.                 case 0x7e:loop_disp=1;single_disp=0;left_move=0;enter=0;break;//循环显示功能
  196.                 case 0x7d:loop_disp=0;single_disp=1;left_move=0;enter=0;break;//单通道显示功能
  197.                 case 0x7b:loop_disp=0;single_disp=0;left_move=1;enter=0;break;//左移显示功能
  198.                 //case 0x77:on_off=0;break;//关机
  199.                }
  200.             }
  201. void measure()//AD转化程序&完成相应功能
  202.             {
  203.                TRISA=0xff;
  204.                ADCON0=channel[disp_num];
  205.                ADCON1=0x80;

  206.                if(enter==1&&single_disp==1)
  207.                {
  208.                   uint adval;
  209.                   GO=1;
  210.                   while(GO)
  211.                   adval=ADRESH;
  212.                   adval=adval<<8|ADRESL;
  213.                   volval=adval/20;
  214.                   onkey_num=key_num;  
  215.                   scan();
  216.                    switched();
  217.                  display(volval,disp_num);
  218.                }
  219.               //display(99,disp_num);
  220.                 while(enter==1&&left_move==1&&on_off==1)
  221.                {left_num=disp_num;
  222.                  while(left_move==1&&on_off==1&&left_num!=8)
  223.                {onkey_num=key_num;  
  224.                   scan();
  225.                    switched();
  226.                   //
  227.                   ADCON0=channel[left_num];
  228.                   uint adval;
  229.                   GO=1;
  230.                   while(GO)
  231.                   adval=ADRESH;
  232.                   adval=adval<<8|ADRESL;
  233.                   volval=adval/20;                  
  234.                getab(volval,left_num);

  235.                while(e!=0)
  236.                {
  237.                   uint disp_times=650;         

  238.                   while(disp_times!=0&&left_move==1)
  239.                   {onkey_num=key_num;  
  240.                    scan();
  241.                    switched();        
  242.                   //left_num=disp_num;   
  243.                      leftdisplay();
  244.                      disp_times--;
  245.                   }
  246.                   e--;
  247.                   if(e==1)
  248.                   {
  249.                  left_num++;
  250.                  leftmove();

  251.                   }
  252.                }
  253.                e=2;
  254.                }
  255.                left_num=0;
  256.                }
  257.                
  258.                
  259.                if(enter==1&&loop_disp==1&&on_off==1)
  260.                {loop_num=disp_num;
  261.                while(loop_disp==1&&on_off==1)
  262.                {

  263.                   while(loop_num!=8&&loop_disp==1&&on_off==1)
  264.                   {
  265.                   uint disp_times=525;//循环次数,完成该次数后刚好显示了一秒钟         
  266.                   while(disp_times!=0&&loop_disp==1&&on_off==1)//循环显示程序
  267.                   {onkey_num=key_num;  
  268.                    scan();//扫描
  269.                    switched();//改变状态字
  270.                   ADCON0=channel[loop_num];//AD转换
  271.                   uint adval;
  272.                   GO=1;
  273.                   while(GO)
  274.                   adval=ADRESH;
  275.                   adval=adval<<8|ADRESL;
  276.                   volval=adval/20;
  277.                   //getab(volval,loop_num);
  278.                   //leftdisplay;
  279.                   display(volval,loop_num);//显示
  280.                      disp_times--;//循环次数自减
  281.                   }
  282.                   loop_num++;//显示了1秒钟后,通道号加一                  
  283.                   }
  284.                   loop_num=0;//disp_num等于8的时候置0
  285.                }
  286.             }
  287.                while(enter==0&&(loop_disp==1||left_move==1))
  288.                {onkey_num=key_num;  
  289.                   scan();//扫描
  290.                    switched();//改变状态字
  291.                   display(0,-1);
  292.                   }            
  293.                   }
  294. void main()//主程序
  295. {
  296.     while(1)
  297.     {  onkey_num=key_num;  
  298.        scan();
  299.        switched();
  300.        //display(volval,disp_num);
  301.        while(on_off==1)
  302.        {onkey_num=key_num;  
  303.         scan();
  304.        switched();
  305.           //left_num=disp_num;
  306.         measure();
  307.        display(volval,disp_num);
  308.        }
  309.        c=-1;
  310.        a=-1;
  311.        b=-1;
  312.         leftdisplay();  
  313.     }
  314. }
复制代码

全部资料51hei下载地址:
电压表备份 试验品.rar (35.2 KB, 下载次数: 156)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:712295 发表于 2020-9-18 16:27 | 显示全部楼层
楼主你好请问PIC这个芯片的AD原理是怎么样的》能说一下嘛
回复

使用道具 举报

ID:821033 发表于 2020-9-25 16:54 | 显示全部楼层
谢谢分享,下载下来学习学习
回复

使用道具 举报

ID:821033 发表于 2020-9-25 16:56 | 显示全部楼层
谢谢楼主分享,下载下来学习学习
回复

使用道具 举报

ID:869201 发表于 2020-12-29 09:26 来自手机 | 显示全部楼层
十分有用
回复

使用道具 举报

ID:982749 发表于 2021-11-30 19:53 | 显示全部楼层
楼主,编译时候显示GO=1是错误的
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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