久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1888|回復: 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 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 免费看黄色大片 | 欧美黄色一级视频 | 久久久少妇 | www.日日日| 亚洲美女网站 | 四虎影音 | 中文字幕一区二区三区乱码 | 国产精品久久久久久99 | 精品一区二区三区在线观看 | 蜜桃视频一区 | 日韩一级黄色片 | 日本久久久久 | 欧美日韩激情视频 | 国产高潮在线 | 成人免费毛片嘿嘿连载视频 | 在线免费观看av网站 | 一本色道久久综合亚洲精品小说 | a级片久久 | 毛片91| 午夜视频免费 | 日韩国产在线 | 国产黄色av | 黄色小视频免费 | 午夜亚洲精品 | 亚洲精品日韩丝袜精品 | 国产精品123区 | 精品一区二区在线播放 | 日韩中文字幕在线观看 | av网站免费在线观看 | 中文字幕第一区综合 | 国产精品视频免费 | 中文字幕亚洲精品 | 欧美a级黄色片 | 久久久www成人免费精品 | 综合伊人 | 三上悠亚激情av一区二区三区 | 久久成人国产 | 久久精品国产亚洲 | 一级片免费在线观看 | 国产黄色在线观看 | a一级黄色片 |