找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1733|回复: 0
收起左侧

单片机转送带计数器设计 附源程序原理图

[复制链接]
ID:1089282 发表于 2023-7-29 08:13 | 显示全部楼层 |阅读模式
目录
1、项目需求分析 2
11、项目目标意义 2
12、功能需求分析 2
13、系统开发环境、工具需求分析与选择 2
14、非功能性需求分析 2
2、项目硬件系统结构 2
21、 系统方案原理图 2
22、AT89C51原理介绍 2
23 、光电开关模块原理 3
24、报警模块原理 4
25、按键模块原理 4
26、数码管显示模块原理 5
27、存储模块原理 5
28、传送带电机驱动模块原理 6
3、系统软件体系架构 6
31 项目软件系统总架构图 6
32 显示子模块流程图 9
33 重要的数据结构、参数和函数分析 12
4、项目运行效果展示 13
5、总结与心得体会 14
6、附录 15

1、项目需求分析

1.1、项目目标意义
工业生产中,很多领域需要自动统计产品的数量,基于光电开关和AT89C51单片机开发的传送带计数器完美解决了传送带上面运送的产品需要人工计数的烦恼,通过该计数器的应用,企业无论是计数效率和准确度方面都有了质的提升而普及自动计数器也具有非常实际的意义,受到广大企业的青睐。
1.2、功能需求分析
通过光电开关检测传送带传送过来的产品,每过一个产品,单片机计数加1,由此实现自动计数功能;设置蜂鸣器在出现异常时可实现报警功能;添加数码管实现计数的显示功能;通过EEPROM存储器,实现计数的存储功能;添加按键实现相关设置功能。
1.3、系统开发环境、工具需求分析与选择
本系统是基于Keil C51的单片机开发环境进行的开发,Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用,基于此我们选择C语言进行编程。
1.4、非功能性需求分析
在电子技术飞速发展的今天,电子产品的智能化和自动化的发展已越来越成熟,每个行业都在寻求自动化来代替人工,基于光电开关和AT89C51单片机开发的传送带计数器使用简单,操作方便,有效节省了人工成本,单位时间内提高了工作效率,给企业带来更大的收益。
2、项目硬件系统结构
2.1系统方案原理图

如图是整个系统实现的框图,从图中我们可以看到整个系统包括单片机模块、按键输入模块、计数模块、存储模块、数码管显示模块、传送带电机模块、蜂鸣器和指示灯报警模块。整个系统通过这几个模块协同工作实现传送带计数器的功能。



2.2AT89C51原理介绍
AT89C51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低电压,高性能CMOS8位微处理器,俗称单片机。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
本系统应用到的AT89C51的I/O输入输出功能:在32个I/O口中选择,实现按键、显示、驱动等功能,I/O口分为P0、P1和P3三大类;P0可以作普通IO口,也可以在读写外部存储器作低8位的地址总线和8位的数据总线;P1口只作为一般IO口;P2作为一般IO口还在在读写外部存储器作高8位的地址总线;P3口除作为一般IO口还为第二输入/输出功能(P3.0 串行数据接入端;P3.1 串行数据发送端;P3.2外中断0输入端 ;P3.3 外中断1输入端;P3.4 定时或计数器TO 的外部输入端;P3.5 定时或计数器T1的外部输入端;P3.6 外部数据存储器写选通信号;P3.7 外部数据存储器读选通信号;)
本系统应用到的定时器功能:实现定时中断功能,AT89C51有T0和T1两个定时/计数器,分别有定时和计数两种模式、4种(T1为3种)工作方式,方式0-方式3,方式0下、计数工作方式时,计数范围是1-8192,定时工作方式时,定时时间的计算公式是:(2^13-计数初值)*机器周期;方式1下,与方式0的差别仅在于计数位数不同,方式1为16位计数,作为定时方式使用时,定时时间的计算公式是:(2^16-计数初值)*机器周期,计数范围是1-65536;方式2下,计数满后自动装入计数初值,精确定时并简化定时初值;方式3只适用于T0,T1不能工作在方式3。
2.3 、光电开关模块原理
光电开关即光电传感器,是光电接近开关的简称,它主要是利用被检测物对光束的遮挡或反射,由同步回路选通电路,从而检测物体有无的。光电开关是传感器的一种,它把发射端和接收端之间光的强弱变化转化为电流的变化以达到探测的目的。例当光电开关被产品遮挡时,输出引脚变低电平,单片机检测到低电平计数一次代表一个产品,当光电开关无遮挡是,输出引脚变高电平,单片机检测到高电平不予计数,代表无产品通过。我们这里使用一个开关模拟他的信号,这个开关接入单片机的P3.4口,当按键按下一次表示检测到一个商品。
2.4、报警模块原理
本系统采用蜂鸣器和LED指示灯做报警元件,蜂鸣器一端接电源,另一端通过三级管接到单片机I/O口进行控制,当需要报警时,单片机控制蜂鸣器的I/O口置高,三极管导通,将蜂鸣器另一端拉低,蜂鸣器导通并鸣响,实现报警。另外LED串联一个限流电阻,一端连接电源,一端连接单片机的P1.1引脚,单片机控制LED亮灭进行指示作用。
2.5、按键模块原理
本系统采用独立按键和矩阵按键结合的方式,独立按键直接用I/O口线构成的单个按键电路,其特点式每个按键单独占用一根I/O口线,每个按键的工作不会影响其他I/O口线的状态。独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一个I/O口线,因此,在按键较多时,I/O口线浪费较大,不宜采用。独立按键的软件常采用查询式结构。先逐位查询没跟I/O口线的输入状态,如某一根I/O口线输入为低电平,则可确认该I/O口线所对应的按键已按下,然后,再转向该键的功能处理程序。矩阵按键是逐行扫描,然后判断有没有按键按下,有按下的时候再判断列,最终确定按键的数值。

2.6、数码管显示模块原理
数码管也称LED数码管,晶美、光电、不同行业人士对数码管的称呼不一样,其实都是同样的产品。数码管按段数可分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元(多一个小数点显示);按能显示多少个“8”可分为1位、2位、3位、4位、5位、6位、7位等数码管;按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管,共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮,当某一字段的阴极为高电平时,相应字段就不亮。共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管,共阴数码管在应用时应将公共极COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮,当某一字段的阳极为低电平时,相应字段就不亮,本系统采用共阳数码管。
2.7、存储模块原理
本系统采用AT24C02存储芯片,AT24C02芯片是以IIC接口的EEPROM器件。所谓EEPROM即电可擦除可编程只读存储器,是ROM的一种。它是只读存储器,即掉电可继续存储数据,而同时又可以在高于普通电压的作用下擦除和重写,这就方便了单片机对其的开发,现在电脑上的ROM很多都是用的EEPROM。
2.8、传送带电机驱动模块原理
本系统采用单片机通过三极管控制继电器驱动直流电机,根据传送带直流电机的功率等参数选用相应的继电器,当单片机控制电机的I/O口为低时,三极管导通,继电器吸合,电机电源端导通,电机运转传送,当单片机控制电机的I/O口为高时,三极管截止,继电器断开,电机电源端断开,电机停止运转。
3、系统软件体系架构
3.1 项目软件系统总架构图
整个系统的实现流程图如图,从图中我们可以看到程序首先对外设进行了初始化,然后读取存储在芯片中的设定数值,接着初始化定时器之后就进入了主循环。主循环首先读取了按键,然后根据按键进行设定和启停等操作,同时判断计数数值是否大于等于设置数值,如果到了就报警提示。最后根据不同的模式显示不同的数值。


/********************************************************************
* 名称 : Main()                 
* 功能 : 主函数               
* 输入 : 无         
* 输出 : 无         
***********************************************************************/
void Main(void)
{
  uchar press_sure_num=0;
  uchar Key_num=0;
  uchar temp=0;

  moto=0;              //关闭电机
  BUZZ=1;      //关闭报警
  Read_set_num();      //读取设定的数值
  Time0_init();             // 定时器初始化

  while(1)
  {           
    Key_num=KEY_Scan(); //扫描按键

    if(set_mode==0)   //非设定模式
    {
      if(Key_num==12)            //启动
      {
        counter_buf[0]=0;counter_buf[1]=0;counter_buf[2]=0;counter_buf[3]=0;   //清除显示
        counter_num=0;         //计数清零
        moto=1;                       //打开电机
          LED=1;
        BUZZ=1; //关闭报警
        EA=1;                           //打开计数
      }
      else if(Key_num==13)//停止
      {
        moto=0;                //关闭电机
          LED=1;
        BUZZ=1;//关闭报警
        EA=0;                    //关闭计数
      }
      if(Key_num==14)     //设置
      {
        set_mode=1;        //设置模式置一
        set_position=1;
        moto=0;                //关闭电机
        EA=0;                   //关闭计数

      }
     }
    else//设定模式
    {
      if(Key_num==11)//按下了确定键
      {
        set_mode=0;//退出设定
        set_position=0;
        counter_buf[0]=0;counter_buf[1]=0;counter_buf[2]=0;counter_buf[3]=0;
          //set_num=(dis_data_buf[0]*1000)+(dis_data_buf[1]*100)+(dis_data_buf[2]*10)+dis_data_buf[3];  //计算出计数的数值
          Write_set_num();
      }
      else if(Key_num<10)//显示的设定值
      {

        dis_data_buf[4-set_position]=Key_num;
        set_position++;
        if(set_position>4)set_position=4;
      }
      else if(Key_num==10)//清除设定
      {
        set_position=1;
        dis_data_buf[0]=0;
        dis_data_buf[1]=0;
        dis_data_buf[2]=0;
        dis_data_buf[3]=0;
      }
    }

    set_num=(dis_data_buf[0]*1000)+(dis_data_buf[1]*100)+(dis_data_buf[2]*10)+dis_data_buf[3];       //计算出计数的数值

    if(counter_num>=set_num)  //如果计数数值大于等于设定的数值就停止
    {
      moto=0;                    //关闭电机
      BUZZ=0;     //打开报警
     LED=0;//

    }                                          
    if(set_mode==0)   //正常模式下显示计数值
    {
      diplay(counter_buf);
    }
    else   //设定模式下显示设定值
    {
      diplay(dis_data_buf);
    }


  }
}


3.2 显示子模块流程图
这里我们介绍的是显示子函数,子函数首先是关闭数码管的显示,这一步称为消引。然后把显示的数据送给其中一个数码管,最后点亮这个数码管,等到下一次轮寻就再调用下一个数码管。


//数码管的显示函数
void diplay(uchar *dis_p)
{
  static uchar temp_num=0;
  static uint flash_time=0;
  //全部关闭消引
  seg_1=0;
  seg_2=0;
  seg_3=0;
  seg_4=0;
  SEG_DATA=SEG_Table[*(dis_p+temp_num)];    //把数据发送给数码管的数据接口
  switch(temp_num)    //动态一次扫描各个数码管
  {
  case 0:
    if(set_position==4)
    {
      if(flash_time<50)     //如果社说的时间小于50那么就打开心事
      {seg_1=1;seg_2=0;seg_3=0;seg_4=0;}
      else if(flash_time<100)//小于100就关闭显示
      {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
      else                                  //大于等于100就重新开始闪烁
      {flash_time=0;}
    }
    else
    {
      seg_1=1;
      seg_2=0;
      seg_3=0;
      seg_4=0;
    }
    break;
  case 1:
    if(set_position==3)
    {
      if(  flash_time<50)
      {seg_1=0;seg_2=1;seg_3=0;seg_4=0;}
      else if(flash_time<100)
      {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
      else
      {flash_time=0;}
    }
    else
    {
      seg_1=0;
      seg_2=1;
      seg_3=0;
      seg_4=0;
    }
    break;
  case 2:
    if(set_position==2)
    {
      if(  flash_time<50)
      {seg_1=0;seg_2=0;seg_3=1;seg_4=0;}
      else if(flash_time<100)
      {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
      else
      {flash_time=0;}
    }
    else
    {
      seg_1=0;
      seg_2=0;
      seg_3=1;
      seg_4=0;
    }
    break;
  case 3:
    if(set_position==1)
    {
      if(  flash_time<50)
      {seg_1=0;seg_2=0;seg_3=0;seg_4=1;}
      else if(flash_time<100)
      {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
      else
      {flash_time=0;}
    }
    else
    {
      seg_1=0;
      seg_2=0;
      seg_3=0;
      seg_4=1;
    }
    break;
  }
  Delay_1ms(2);

  temp_num++;
  if(temp_num>3) temp_num=0;//循环四次

  flash_time++;
  if(set_position==0)flash_time=0;      //闪烁


}
3.3 重要的数据结构、参数和函数分析
//读取设定的目标数值
void Read_set_num(void)
{
   uchar i=0;
   for(i=0;i<4;i++)
   {
    dis_data_buf[ i]=read_rom(i);
[ i]    if(dis_data_buf[ i]>9)break;
    }
    if(i==4)
    {
          set_num=(dis_data_buf[0]*1000)+(dis_data_buf[1]*100)+(dis_data_buf[2]*10)+dis_data_buf[3];     //计算出计数的数值
   }
   else
   {
     for(i=0;i<4;i++)
     {
        dis_data_buf[ i]=0;
        write_rom(i,dis_data_buf[ i]);
     }
   }
}
这里我们分析一下读取设定目标数值的子函数,这个子函数在程序的一开始调用一次,主要是读取上一次存储的数据,防止其掉电丢失。首选读24C02得到不同地址内的数据,然后根据存入的顺序把数据拼接成设定值给后面使用。
4、项目运行效果展示
  这是初始状态没有进行操作的时候,如图
然后我们点击启动按钮,可以看到电机开始转动了,如图
我们按下模拟光电的开关,实际数值增加到设定值,此时电机停止并报警,如图
5、总结与心得体会
这个设计过程中,我们通过在原有的计数器系统进行了改进,使之增添了设置、启动、停止等的三个控制功能,并添加了报警、显示、存储等功能,使之成为一个更加适用,功能更加完备的属于自己的一个系统。设计结果能够符合题意,成功完成了此次设计要求,这个过程中,我们花费了大量的时间和精力,更重要的是,我们在学会创新的基础上,同时还懂得合作精神的重要性,学会了与他人合作。我们掌握的仅仅是理论知识,如何去锻炼我们的实践能力?如何把我们所学的专业基础课理论知识运用到实践中去呢?我想做类似设计就为我们提供了良好的实践平台。
       在这次设计中,我们运用到了以前所学的专业知识,如:C语言、模拟和数字电路知识等。虽然过去从未独立应用过它们,但在学习的过程中带着问题去学效率很高,这是我做这次设计的又一收获。
基于Keil C51的单片机开发环境应用范围广泛,功能强大,但由于自己应用不够熟悉,出现了很多不规范的情况,使得在调试过程中遇到很多困难,这是自己软件开发能力不足的表现,有待提高。本系统通过按键进行设定计数功能,需要人为现场近距离操作,可考虑通过遥控设定,改进方案后,可远距离操作,更好的节省人力。


6、附录

单片机源程序如下:
  1. //包含头文件
  2. #include<reg52.h>
  3. #include<intrins.h>

  4. //宏定义方便使用
  5. #define uint unsigned int
  6. #define uchar unsigned char
  7. #define AT24C02               255
  8. #define AT24C16               2047
  9. #define AT24CXX   AT24C02                             //此处修改器件类型24c02或者24c256

  10. sbit SCL = P1^6; //24Cxx接线
  11. sbit SDA = P1^7;


  12. //数码管位选接口
  13. sbit seg_1=P3^0;
  14. sbit seg_2=P3^1;
  15. sbit seg_3=P3^2;
  16. sbit seg_4=P3^3;

  17. #define SEG_DATA            P0                //数码管的数据接口


  18. //独立按键
  19. sbit K1=P3^7;
  20. sbit K2=P3^6;
  21. sbit K3=P3^5;

  22. //矩阵按键的接口
  23. #define K_PORT                 P2

  24. //蜂鸣器引脚
  25. sbit BUZZ=P1^0;
  26. //LED引脚
  27. sbit LED=P1^1;

  28. //电机的控机制口
  29. sbit moto=P1^2;


  30. uchar code SEG_Table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//CA共阳
  31. char dis_data_buf[4]={0,0,0,1};
  32. uchar counter_buf[4]={0,0,0,0};
  33. unsigned long int set_num=0;
  34. unsigned long int counter_num=0;
  35. uchar set_position=0;
  36. uchar set_mode=0;


  37. void Delay_1ms(uint i)//1ms延时
  38. {
  39.   uchar x,j;
  40.   for(j=0;j<i;j++)
  41.     for(x=0;x<=148;x++);      
  42. }

  43. void delay_us(uint i)
  44. {
  45.           uint t;
  46.          for(t=0;t<i;t++)
  47.          _nop_();

  48. }



  49. /*开始I2C数据发送或接收*/
  50. void start_rom()//在时钟线为高,数据线从高电平跳到低电平时,开始传送
  51. {
  52.    SDA=1;           //数据先
  53.    delay_us(2);
  54.    SCL=1;           //时钟线为高,等数据线下降才开始
  55.   delay_us(5);
  56.    SDA=0;           //数据线下降拉,启动了
  57.          delay_us(5);
  58.    SCL=0;           
  59. }

  60. /*结束数据传送*/
  61. void stop_rom()
  62. {  
  63.    SDA=0;            //时钟线为高时,数据线上升沿为结束信号
  64.          delay_us(2);
  65.    SCL=1;
  66.          delay_us(4);
  67.    SDA=1;
  68.          delay_us(4);
  69.    SCL=0;
  70. }

  71. //************************************************************************//
  72. //函数名称:void ack_rom()
  73. //函数功能:ROM应答信号
  74. //**********************************************************************//
  75. void ack_rom()
  76. {
  77.          SDA=1;
  78.          delay_us(2);
  79.          SCL=0;
  80.          delay_us(2);
  81.          SCL=1;
  82.          delay_us(2);
  83.          SCL=0;
  84.          delay_us(2);
  85. }

  86. //***********************************************************************//
  87. //函数名称:void no_ack_rom()
  88. //函数功能:无需应答
  89. //***********************************************************************//
  90. void no_ack_rom()
  91. {
  92.          SDA=1;
  93.          delay_us(2);
  94.          SCL=1;
  95.          delay_us(2);
  96.          SCL=0;
  97.          delay_us(2);
  98. }

  99. //**********************************************//
  100. //函数名称:void write_byte_rom(uchar data)
  101. //函数功能:向ROM 写入字节
  102. //传入参数:data 待写入的字节
  103. //返回参数:无
  104. //**********************************************//
  105. void write_byte_rom(uchar dataa)
  106. {
  107.          uchar i=8;
  108.          SDA = 0;
  109.          SCL=0;
  110.          _nop_();_nop_();_nop_();_nop_();_nop_();
  111.          while(i--)//写数据循环,从高位开始
  112.          {
  113.                   if((dataa & 0x80)) SDA=1; //将IO 口拉高,写入1
  114.                    else SDA=0; //将IO 口拉低,写入0
  115.                    delay_us(5);
  116.                    dataa<<=1;
  117.                    SCL=1;
  118.                    delay_us(5);
  119.                    SCL=0;
  120.                    delay_us(5);
  121.          }
  122. }

  123. uchar read_byte_rom()
  124. {
  125.          uchar i,k;
  126.          for(i=0;i<8;i++)
  127.          {
  128.                    SCL=1;
  129.                    delay_us(5);
  130.                    k=(k<<1)|SDA;
  131.                    SCL=0;
  132.                    delay_us(5);            
  133.          }
  134.          return k;
  135. }

  136. uchar read_rom(uint add)
  137. {
  138.          uchar da;
  139.          start_rom();
  140.          write_byte_rom(0xa0);
  141.          ack_rom();      
  142.          if(AT24CXX>AT24C16)
  143.          {
  144.          //write_byte_rom(addr/256); //写入地址高八位
  145.          write_byte_rom(add>>8); //写入地址高八位
  146.          ack_rom();
  147.          write_byte_rom(add%256); //写入地址低八位
  148.          //write_byte_rom(addr&0xff); //写入地址低八位
  149.          }
  150.          else
  151.          write_byte_rom(add);

  152.          ack_rom();
  153.          start_rom();
  154.          write_byte_rom(0xa1);
  155.          ack_rom();
  156.          da=read_byte_rom();
  157.          no_ack_rom();
  158.          stop_rom();
  159.          return da;
  160.                   
  161. }
  162.         
  163. //**********************************************//
  164. //函数名称:void write_rom(uchar addr,uchar data)
  165. //函数功能:写数据到ROM
  166. //传入参数:addr 写入的地址
  167. //返回参数:read_data 待写入的数据
  168. //**********************************************//
  169. void write_rom(uint addr,uchar dataa)
  170. {
  171.          start_rom();
  172.          write_byte_rom(0xa0); //选择写操作
  173.          ack_rom();
  174.          if(AT24CXX>AT24C16)
  175.          {
  176.          //write_byte_rom(addr/256); //写入地址高八位
  177.          write_byte_rom(addr>>8); //写入地址高八位
  178.          ack_rom();
  179.          write_byte_rom(addr%256); //写入地址低八位
  180.          //write_byte_rom(addr&0xff); //写入地址低八位
  181.          }
  182.          else
  183.                    write_byte_rom(addr);
  184.          ack_rom();
  185.          write_byte_rom(dataa); //写入数据
  186.         
  187.          ack_rom();
  188.          stop_rom();
  189.         
  190. }



  191. //*********************************
  192. //按键扫描程序
  193. //*********************************
  194. uchar KEY_Scan()
  195. {      
  196.   uchar table[3]={0xB0,0xd0,0xE0};
  197.   uchar temp=0,temp_data=0,temp_key_num=0XFF;
  198.   uchar i=0,k=0;
  199.   static uchar key_up=0;

  200.   K_PORT = 0xF0;
  201.   if(key_up==0)      
  202.   {
  203.    
  204.     for(k=0;k<4;k++)
  205.     {
  206.       temp_data=~(1<<k);  //逐行拉低判断有没有按键按下
  207.       _nop_();
  208.       K_PORT=temp_data;
  209.       if(K_PORT!=temp_data)//有按键按下
  210.       {
  211.         Delay_1ms(10);//去抖动
  212.         if(K_PORT!=temp_data)//有按键按下
  213.         {
  214.           key_up=1;
  215.           temp=K_PORT&0xf0;  //取高字节,即列
  216.           for(i=0;i<3;i++)
  217.           {
  218.             if(temp==table[i])
  219.             {
  220.               break;
  221.             }
  222.           }
  223.           if(i!=3)//有效按键
  224.           {
  225.             temp_key_num=i+k*3;    //获取按键
  226.             break;
  227.           }
  228.          
  229.         }
  230.       }
  231.     }
  232.    
  233.     //判断独立按键
  234.     if((K1==0||K2==0||K3==0))
  235.     {
  236.       key_up=1;
  237.       Delay_1ms(10);//去抖动
  238.       if(K1==0)temp_key_num=12;
  239.       else if(K2==0)temp_key_num=13;
  240.       else if(K3==0)temp_key_num=14;
  241.     }
  242.    
  243.   }
  244.   else
  245.   {
  246.     if((K_PORT==0xf0)&&(K1==1)&&(K2==1)&&(K3==1))key_up=0;    //松开按键
  247.     temp_key_num=0XFF;
  248.   }      
  249.   return temp_key_num;// 返回键值
  250. }

  251. //数码管的显示函数
  252. void diplay(uchar *dis_p)
  253. {
  254.   static uchar temp_num=0;
  255.   static uint flash_time=0;
  256.   //全部关闭消引
  257.   seg_1=0;
  258.   seg_2=0;
  259.   seg_3=0;
  260.   seg_4=0;
  261.   SEG_DATA=SEG_Table[*(dis_p+temp_num)];     //把数据发送给数码管的数据接口
  262.   switch(temp_num)      //动态一次扫描各个数码管
  263.   {
  264.   case 0:
  265.     if(set_position==4)
  266.     {
  267.       if(flash_time<50) //如果社说的时间小于50那么就打开心事
  268.       {seg_1=1;seg_2=0;seg_3=0;seg_4=0;}
  269.       else if(flash_time<100)//小于100就关闭显示
  270.       {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
  271.       else                                            //大于等于100就重新开始闪烁
  272.       {flash_time=0;}
  273.     }
  274.     else
  275.     {
  276.       seg_1=1;
  277.       seg_2=0;
  278.       seg_3=0;
  279.       seg_4=0;
  280.     }
  281.     break;
  282.   case 1:
  283.     if(set_position==3)
  284.     {
  285.       if( flash_time<50)
  286.       {seg_1=0;seg_2=1;seg_3=0;seg_4=0;}
  287.       else if(flash_time<100)
  288.       {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
  289.       else
  290.       {flash_time=0;}
  291.     }
  292.     else
  293.     {
  294.       seg_1=0;
  295.       seg_2=1;
  296.       seg_3=0;
  297.       seg_4=0;
  298.     }
  299.     break;
  300.   case 2:
  301.     if(set_position==2)
  302.     {
  303.       if( flash_time<50)
  304.       {seg_1=0;seg_2=0;seg_3=1;seg_4=0;}
  305.       else if(flash_time<100)
  306.       {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
  307.       else
  308.       {flash_time=0;}
  309.     }
  310.     else
  311.     {
  312.       seg_1=0;
  313.       seg_2=0;
  314.       seg_3=1;
  315.       seg_4=0;
  316.     }
  317.     break;
  318.   case 3:
  319.     if(set_position==1)
  320.     {
  321.       if( flash_time<50)
  322.       {seg_1=0;seg_2=0;seg_3=0;seg_4=1;}
  323.       else if(flash_time<100)
  324.       {seg_1=0;seg_2=0;seg_3=0;seg_4=0;}
  325.       else
  326.       {flash_time=0;}
  327.     }
  328.     else
  329.     {
  330.       seg_1=0;
  331.       seg_2=0;
  332.       seg_3=0;
  333.       seg_4=1;
  334.     }
  335.     break;
  336.   }
  337.   Delay_1ms(2);

  338.   temp_num++;
  339.   if(temp_num>3) temp_num=0;//循环四次

  340.   flash_time++;
  341.   if(set_position==0)flash_time=0;            //闪烁


  342. }
  343. //计数器0的初始化
  344. void Time0_init(void)
  345. {
  346.   TMOD=0x05;
  347.   TH0=0xff;
  348.   TL0=0xff;
  349.   ET0=1;
  350.   TR0=1;
  351.   EA=1;

  352. }

  353. //读取设定的目标数值
  354. void Read_set_num(void)
  355. {
  356.          uchar i=0;
  357.          for(i=0;i<4;i++)
  358.          {
  359.           dis_data_buf[i]=read_rom(i);
  360.           if(dis_data_buf[i]>9)break;
  361.           }
  362.           if(i==4)
  363.           {
  364.                    set_num=(dis_data_buf[0]*1000)+(dis_data_buf[1]*100)+(dis_data_buf[2]*10)+dis_data_buf[3];     //计算出计数的数值
  365.          }
  366.          else
  367.          {
  368.            for(i=0;i<4;i++)
  369.            {
  370.                 dis_data_buf[i]=0;
  371.                 write_rom(i,dis_data_buf[i]);
  372.            }
  373.          }
  374. }
  375. //向eeprom中写入存储数据
  376. void Write_set_num()
  377. {
  378.    uchar i=0;
  379.    for(i=0;i<4;i++)
  380.           write_rom(i,dis_data_buf[i]);

  381.   
  382. }
  383. /********************************************************************
  384. * 名称 : Main()                        
  385. * 功能 : 主函数                     
  386. * 输入 : 无            
  387. * 输出 : 无            
  388. ***********************************************************************/
  389. void Main(void)
  390. {
  391.   uchar press_sure_num=0;
  392.   uchar Key_num=0;
  393.   uchar temp=0;

  394.   moto=0;                 //关闭电机
  395.   BUZZ=1;       //关闭报警
  396.   Read_set_num();         //读取设定的数值
  397.   Time0_init();                  // 定时器初始化

  398.   while(1)
  399.   {            
  400.     Key_num=KEY_Scan();     //扫描按键
  401.    
  402.     if(set_mode==0)      //非设定模式
  403.     {
  404.       if(Key_num==12)          //启动
  405.       {
  406.         counter_buf[0]=0;counter_buf[1]=0;counter_buf[2]=0;counter_buf[3]=0;    //清除显示
  407.         counter_num=0;               //计数清零
  408.         moto=1;                               //打开电机
  409.                    LED=1;
  410.         BUZZ=1;  //关闭报警
  411.         EA=1;                                    //打开计数
  412.       }
  413.       else if(Key_num==13)//停止
  414.       {
  415.         moto=0;                     //关闭电机
  416.                    LED=1;
  417.         BUZZ=1;//关闭报警
  418.         EA=0;                          //关闭计数
  419.       }
  420.       if(Key_num==14) //设置
  421.       {
  422.         set_mode=1;            //设置模式置一
  423.         set_position=1;
  424.         moto=0;                     //关闭电机     
  425.         EA=0;                         //关闭计数
  426.       
  427.       }
  428.      
  429.      
  430.     }
  431.     else//设定模式
  432.     {
  433.       if(Key_num==11)//按下了确定键
  434.       {
  435.         set_mode=0;//退出设定
  436.         set_position=0;
  437.         counter_buf[0]=0;counter_buf[1]=0;counter_buf[2]=0;counter_buf[3]=0;
  438.                    //set_num=(dis_data_buf[0]*1000)+(dis_data_buf[1]*100)+(dis_data_buf[2]*10)+dis_data_buf[3]; //计算出计数的数值
  439.                    Write_set_num();
  440.       }
  441.       else if(Key_num<10)//显示的设定值
  442.       {
  443.       
  444.         dis_data_buf[4-set_position]=Key_num;
  445.         set_position++;
  446.         if(set_position>4)set_position=4;
  447.       }
  448.       else if(Key_num==10)//清除设定
  449.       {
  450.         set_position=1;
  451.         dis_data_buf[0]=0;
  452.         dis_data_buf[1]=0;
  453.         dis_data_buf[2]=0;
  454.         dis_data_buf[3]=0;
  455.       }
  456.     }      
  457.    
  458.     set_num=(dis_data_buf[0]*1000)+(dis_data_buf[1]*100)+(dis_data_buf[2]*10)+dis_data_buf[3];     //计算出计数的数值
  459.    
  460.     if(counter_num>=set_num)  //如果计数数值大于等于设定的数值就停止
  461.     {
  462.       moto=0;                          //关闭电机
  463.       BUZZ=0;       //打开报警
  464.            LED=0;//

  465.     }                                                               
  466.     if(set_mode==0)      //正常模式下显示计数值
  467.     {
  468.       diplay(counter_buf);
  469.     }
  470.     else  //设定模式下显示设定值
  471.     {
  472.       diplay(dis_data_buf);
  473.     }
  474.    
  475.    
  476.   }
  477. }

  478. //计数器0中断
  479. void Time0_counter() interrupt 1
  480. {
  481.   TH0=0xff;
  482.   TL0=0xff;

  483.   if(TF0==0)
  484.   {
  485.     if(counter_num>9999)counter_num=0; //最大计数到9999,然后从零开始
  486.     else
  487.     {
  488.       counter_num++;           //计数加一
  489.       counter_buf[3]++;
  490.       if(counter_buf[3]>9)  //个位大于9十位就加一
  491.       {
  492.         counter_buf[3]=0;
  493.         counter_buf[2]++;
  494.       }
  495.       if(counter_buf[2]>9)  //十位大于9百位就加一
  496.       {
  497.         counter_buf[2]=0;
  498.         counter_buf[1]++;
  499.       }
  500.       if(counter_buf[1]>9)
  501.       {
  502.         counter_buf[1]=0;
  503.         counter_buf[0]++;
  504.       }
  505.       if(counter_buf[0]>9)
  506.       {
  507.         counter_buf[0]=0;
  508.       }
  509.     }
  510.   }
  511. }
复制代码

评分

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

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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