找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 1865|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

單片機(jī)轉(zhuǎn)送帶計(jì)數(shù)器設(shè)計(jì) 附源程序原理圖

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:1089282 發(fā)表于 2023-7-29 08:13 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
目錄
1、項(xiàng)目需求分析 2
11、項(xiàng)目目標(biāo)意義 2
12、功能需求分析 2
13、系統(tǒng)開發(fā)環(huán)境、工具需求分析與選擇 2
14、非功能性需求分析 2
2、項(xiàng)目硬件系統(tǒng)結(jié)構(gòu) 2
21、 系統(tǒng)方案原理圖 2
22、AT89C51原理介紹 2
23 、光電開關(guān)模塊原理 3
24、報(bào)警模塊原理 4
25、按鍵模塊原理 4
26、數(shù)碼管顯示模塊原理 5
27、存儲(chǔ)模塊原理 5
28、傳送帶電機(jī)驅(qū)動(dòng)模塊原理 6
3、系統(tǒng)軟件體系架構(gòu) 6
31 項(xiàng)目軟件系統(tǒng)總架構(gòu)圖 6
32 顯示子模塊流程圖 9
33 重要的數(shù)據(jù)結(jié)構(gòu)、參數(shù)和函數(shù)分析 12
4、項(xiàng)目運(yùn)行效果展示 13
5、總結(jié)與心得體會(huì) 14
6、附錄 15

1、項(xiàng)目需求分析

1.1、項(xiàng)目目標(biāo)意義
工業(yè)生產(chǎn)中,很多領(lǐng)域需要自動(dòng)統(tǒng)計(jì)產(chǎn)品的數(shù)量,基于光電開關(guān)和AT89C51單片機(jī)開發(fā)的傳送帶計(jì)數(shù)器完美解決了傳送帶上面運(yùn)送的產(chǎn)品需要人工計(jì)數(shù)的煩惱,通過該計(jì)數(shù)器的應(yīng)用,企業(yè)無論是計(jì)數(shù)效率和準(zhǔn)確度方面都有了質(zhì)的提升而普及自動(dòng)計(jì)數(shù)器也具有非常實(shí)際的意義,受到廣大企業(yè)的青睞。
1.2、功能需求分析
通過光電開關(guān)檢測(cè)傳送帶傳送過來的產(chǎn)品,每過一個(gè)產(chǎn)品,單片機(jī)計(jì)數(shù)加1,由此實(shí)現(xiàn)自動(dòng)計(jì)數(shù)功能;設(shè)置蜂鳴器在出現(xiàn)異常時(shí)可實(shí)現(xiàn)報(bào)警功能;添加數(shù)碼管實(shí)現(xiàn)計(jì)數(shù)的顯示功能;通過EEPROM存儲(chǔ)器,實(shí)現(xiàn)計(jì)數(shù)的存儲(chǔ)功能;添加按鍵實(shí)現(xiàn)相關(guān)設(shè)置功能。
1.3、系統(tǒng)開發(fā)環(huán)境、工具需求分析與選擇
本系統(tǒng)是基于Keil C51的單片機(jī)開發(fā)環(huán)境進(jìn)行的開發(fā),Keil C51是美國(guó)Keil Software公司出品的51系列兼容單片機(jī)C語(yǔ)言軟件開發(fā)系統(tǒng),與匯編相比,C語(yǔ)言在功能上、結(jié)構(gòu)性、可讀性、可維護(hù)性上有明顯的優(yōu)勢(shì),因而易學(xué)易用,基于此我們選擇C語(yǔ)言進(jìn)行編程。
1.4、非功能性需求分析
在電子技術(shù)飛速發(fā)展的今天,電子產(chǎn)品的智能化和自動(dòng)化的發(fā)展已越來越成熟,每個(gè)行業(yè)都在尋求自動(dòng)化來代替人工,基于光電開關(guān)和AT89C51單片機(jī)開發(fā)的傳送帶計(jì)數(shù)器使用簡(jiǎn)單,操作方便,有效節(jié)省了人工成本,單位時(shí)間內(nèi)提高了工作效率,給企業(yè)帶來更大的收益。
2、項(xiàng)目硬件系統(tǒng)結(jié)構(gòu)
2.1系統(tǒng)方案原理圖

如圖是整個(gè)系統(tǒng)實(shí)現(xiàn)的框圖,從圖中我們可以看到整個(gè)系統(tǒng)包括單片機(jī)模塊、按鍵輸入模塊、計(jì)數(shù)模塊、存儲(chǔ)模塊、數(shù)碼管顯示模塊、傳送帶電機(jī)模塊、蜂鳴器和指示燈報(bào)警模塊。整個(gè)系統(tǒng)通過這幾個(gè)模塊協(xié)同工作實(shí)現(xiàn)傳送帶計(jì)數(shù)器的功能。



2.2、AT89C51原理介紹
AT89C51是一種帶4K字節(jié)閃爍可編程可擦除只讀存儲(chǔ)器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低電壓,高性能CMOS8位微處理器,俗稱單片機(jī)。該器件采用ATMEL高密度非易失存儲(chǔ)器制造技術(shù)制造,與工業(yè)標(biāo)準(zhǔn)的MCS-51指令集和輸出管腳相兼容。由于將多功能8位CPU和閃爍存儲(chǔ)器組合在單個(gè)芯片中,ATMEL的AT89C51是一種高效微控制器,為很多嵌入式控制系統(tǒng)提供了一種靈活性高且價(jià)廉的方案。
本系統(tǒng)應(yīng)用到的AT89C51的I/O輸入輸出功能:在32個(gè)I/O口中選擇,實(shí)現(xiàn)按鍵、顯示、驅(qū)動(dòng)等功能,I/O口分為P0、P1和P3三大類;P0可以作普通IO口,也可以在讀寫外部存儲(chǔ)器作低8位的地址總線和8位的數(shù)據(jù)總線;P1口只作為一般IO口;P2作為一般IO口還在在讀寫外部存儲(chǔ)器作高8位的地址總線;P3口除作為一般IO口還為第二輸入/輸出功能(P3.0 串行數(shù)據(jù)接入端;P3.1 串行數(shù)據(jù)發(fā)送端;P3.2外中斷0輸入端 ;P3.3 外中斷1輸入端;P3.4 定時(shí)或計(jì)數(shù)器TO 的外部輸入端;P3.5 定時(shí)或計(jì)數(shù)器T1的外部輸入端;P3.6 外部數(shù)據(jù)存儲(chǔ)器寫選通信號(hào);P3.7 外部數(shù)據(jù)存儲(chǔ)器讀選通信號(hào);)
本系統(tǒng)應(yīng)用到的定時(shí)器功能:實(shí)現(xiàn)定時(shí)中斷功能,AT89C51有T0和T1兩個(gè)定時(shí)/計(jì)數(shù)器,分別有定時(shí)和計(jì)數(shù)兩種模式、4種(T1為3種)工作方式,方式0-方式3,方式0下、計(jì)數(shù)工作方式時(shí),計(jì)數(shù)范圍是1-8192,定時(shí)工作方式時(shí),定時(shí)時(shí)間的計(jì)算公式是:(2^13-計(jì)數(shù)初值)*機(jī)器周期;方式1下,與方式0的差別僅在于計(jì)數(shù)位數(shù)不同,方式1為16位計(jì)數(shù),作為定時(shí)方式使用時(shí),定時(shí)時(shí)間的計(jì)算公式是:(2^16-計(jì)數(shù)初值)*機(jī)器周期,計(jì)數(shù)范圍是1-65536;方式2下,計(jì)數(shù)滿后自動(dòng)裝入計(jì)數(shù)初值,精確定時(shí)并簡(jiǎn)化定時(shí)初值;方式3只適用于T0,T1不能工作在方式3。
2.3 、光電開關(guān)模塊原理
光電開關(guān)即光電傳感器,是光電接近開關(guān)的簡(jiǎn)稱,它主要是利用被檢測(cè)物對(duì)光束的遮擋或反射,由同步回路選通電路,從而檢測(cè)物體有無的。光電開關(guān)是傳感器的一種,它把發(fā)射端和接收端之間光的強(qiáng)弱變化轉(zhuǎn)化為電流的變化以達(dá)到探測(cè)的目的。例當(dāng)光電開關(guān)被產(chǎn)品遮擋時(shí),輸出引腳變低電平,單片機(jī)檢測(cè)到低電平計(jì)數(shù)一次代表一個(gè)產(chǎn)品,當(dāng)光電開關(guān)無遮擋是,輸出引腳變高電平,單片機(jī)檢測(cè)到高電平不予計(jì)數(shù),代表無產(chǎn)品通過。我們這里使用一個(gè)開關(guān)模擬他的信號(hào),這個(gè)開關(guān)接入單片機(jī)的P3.4口,當(dāng)按鍵按下一次表示檢測(cè)到一個(gè)商品。
2.4、報(bào)警模塊原理
本系統(tǒng)采用蜂鳴器和LED指示燈做報(bào)警元件,蜂鳴器一端接電源,另一端通過三級(jí)管接到單片機(jī)I/O口進(jìn)行控制,當(dāng)需要報(bào)警時(shí),單片機(jī)控制蜂鳴器的I/O口置高,三極管導(dǎo)通,將蜂鳴器另一端拉低,蜂鳴器導(dǎo)通并鳴響,實(shí)現(xiàn)報(bào)警。另外LED串聯(lián)一個(gè)限流電阻,一端連接電源,一端連接單片機(jī)的P1.1引腳,單片機(jī)控制LED亮滅進(jìn)行指示作用。
2.5、按鍵模塊原理
本系統(tǒng)采用獨(dú)立按鍵和矩陣按鍵結(jié)合的方式,獨(dú)立按鍵直接用I/O口線構(gòu)成的單個(gè)按鍵電路,其特點(diǎn)式每個(gè)按鍵單獨(dú)占用一根I/O口線,每個(gè)按鍵的工作不會(huì)影響其他I/O口線的狀態(tài)。獨(dú)立式按鍵電路配置靈活,軟件結(jié)構(gòu)簡(jiǎn)單,但每個(gè)按鍵必須占用一個(gè)I/O口線,因此,在按鍵較多時(shí),I/O口線浪費(fèi)較大,不宜采用。獨(dú)立按鍵的軟件常采用查詢式結(jié)構(gòu)。先逐位查詢沒跟I/O口線的輸入狀態(tài),如某一根I/O口線輸入為低電平,則可確認(rèn)該I/O口線所對(duì)應(yīng)的按鍵已按下,然后,再轉(zhuǎn)向該鍵的功能處理程序。矩陣按鍵是逐行掃描,然后判斷有沒有按鍵按下,有按下的時(shí)候再判斷列,最終確定按鍵的數(shù)值。

2.6、數(shù)碼管顯示模塊原理
數(shù)碼管也稱LED數(shù)碼管,晶美、光電、不同行業(yè)人士對(duì)數(shù)碼管的稱呼不一樣,其實(shí)都是同樣的產(chǎn)品。數(shù)碼管按段數(shù)可分為七段數(shù)碼管和八段數(shù)碼管,八段數(shù)碼管比七段數(shù)碼管多一個(gè)發(fā)光二極管單元(多一個(gè)小數(shù)點(diǎn)顯示);按能顯示多少個(gè)“8”可分為1位、2位、3位、4位、5位、6位、7位等數(shù)碼管;按發(fā)光二極管單元連接方式可分為共陽(yáng)極數(shù)碼管和共陰極數(shù)碼管。共陽(yáng)數(shù)碼管是指將所有發(fā)光二極管的陽(yáng)極接到一起形成公共陽(yáng)極(COM)的數(shù)碼管,共陽(yáng)數(shù)碼管在應(yīng)用時(shí)應(yīng)將公共極COM接到+5V,當(dāng)某一字段發(fā)光二極管的陰極為低電平時(shí),相應(yīng)字段就點(diǎn)亮,當(dāng)某一字段的陰極為高電平時(shí),相應(yīng)字段就不亮。共陰數(shù)碼管是指將所有發(fā)光二極管的陰極接到一起形成公共陰極(COM)的數(shù)碼管,共陰數(shù)碼管在應(yīng)用時(shí)應(yīng)將公共極COM接到地線GND上,當(dāng)某一字段發(fā)光二極管的陽(yáng)極為高電平時(shí),相應(yīng)字段就點(diǎn)亮,當(dāng)某一字段的陽(yáng)極為低電平時(shí),相應(yīng)字段就不亮,本系統(tǒng)采用共陽(yáng)數(shù)碼管。
2.7、存儲(chǔ)模塊原理
本系統(tǒng)采用AT24C02存儲(chǔ)芯片,AT24C02芯片是以IIC接口的EEPROM器件。所謂EEPROM即電可擦除可編程只讀存儲(chǔ)器,是ROM的一種。它是只讀存儲(chǔ)器,即掉電可繼續(xù)存儲(chǔ)數(shù)據(jù),而同時(shí)又可以在高于普通電壓的作用下擦除和重寫,這就方便了單片機(jī)對(duì)其的開發(fā),現(xiàn)在電腦上的ROM很多都是用的EEPROM。
2.8、傳送帶電機(jī)驅(qū)動(dòng)模塊原理
本系統(tǒng)采用單片機(jī)通過三極管控制繼電器驅(qū)動(dòng)直流電機(jī),根據(jù)傳送帶直流電機(jī)的功率等參數(shù)選用相應(yīng)的繼電器,當(dāng)單片機(jī)控制電機(jī)的I/O口為低時(shí),三極管導(dǎo)通,繼電器吸合,電機(jī)電源端導(dǎo)通,電機(jī)運(yùn)轉(zhuǎn)傳送,當(dāng)單片機(jī)控制電機(jī)的I/O口為高時(shí),三極管截止,繼電器斷開,電機(jī)電源端斷開,電機(jī)停止運(yùn)轉(zhuǎn)。
3、系統(tǒng)軟件體系架構(gòu)
3.1 項(xiàng)目軟件系統(tǒng)總架構(gòu)圖
整個(gè)系統(tǒng)的實(shí)現(xiàn)流程圖如圖,從圖中我們可以看到程序首先對(duì)外設(shè)進(jìn)行了初始化,然后讀取存儲(chǔ)在芯片中的設(shè)定數(shù)值,接著初始化定時(shí)器之后就進(jìn)入了主循環(huán)。主循環(huán)首先讀取了按鍵,然后根據(jù)按鍵進(jìn)行設(shè)定和啟停等操作,同時(shí)判斷計(jì)數(shù)數(shù)值是否大于等于設(shè)置數(shù)值,如果到了就報(bào)警提示。最后根據(jù)不同的模式顯示不同的數(shù)值。


/********************************************************************
* 名稱 : Main()                 
* 功能 : 主函數(shù)               
* 輸入 : 無         
* 輸出 : 無         
***********************************************************************/
void Main(void)
{
  uchar press_sure_num=0;
  uchar Key_num=0;
  uchar temp=0;

  moto=0;              //關(guān)閉電機(jī)
  BUZZ=1;      //關(guān)閉報(bào)警
  Read_set_num();      //讀取設(shè)定的數(shù)值
  Time0_init();             // 定時(shí)器初始化

  while(1)
  {           
    Key_num=KEY_Scan(); //掃描按鍵

    if(set_mode==0)   //非設(shè)定模式
    {
      if(Key_num==12)            //啟動(dòng)
      {
        counter_buf[0]=0;counter_buf[1]=0;counter_buf[2]=0;counter_buf[3]=0;   //清除顯示
        counter_num=0;         //計(jì)數(shù)清零
        moto=1;                       //打開電機(jī)
          LED=1;
        BUZZ=1; //關(guān)閉報(bào)警
        EA=1;                           //打開計(jì)數(shù)
      }
      else if(Key_num==13)//停止
      {
        moto=0;                //關(guān)閉電機(jī)
          LED=1;
        BUZZ=1;//關(guān)閉報(bào)警
        EA=0;                    //關(guān)閉計(jì)數(shù)
      }
      if(Key_num==14)     //設(shè)置
      {
        set_mode=1;        //設(shè)置模式置一
        set_position=1;
        moto=0;                //關(guān)閉電機(jī)
        EA=0;                   //關(guān)閉計(jì)數(shù)

      }
     }
    else//設(shè)定模式
    {
      if(Key_num==11)//按下了確定鍵
      {
        set_mode=0;//退出設(shè)定
        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];  //計(jì)算出計(jì)數(shù)的數(shù)值
          Write_set_num();
      }
      else if(Key_num<10)//顯示的設(shè)定值
      {

        dis_data_buf[4-set_position]=Key_num;
        set_position++;
        if(set_position>4)set_position=4;
      }
      else if(Key_num==10)//清除設(shè)定
      {
        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];       //計(jì)算出計(jì)數(shù)的數(shù)值

    if(counter_num>=set_num)  //如果計(jì)數(shù)數(shù)值大于等于設(shè)定的數(shù)值就停止
    {
      moto=0;                    //關(guān)閉電機(jī)
      BUZZ=0;     //打開報(bào)警
     LED=0;//

    }                                          
    if(set_mode==0)   //正常模式下顯示計(jì)數(shù)值
    {
      diplay(counter_buf);
    }
    else   //設(shè)定模式下顯示設(shè)定值
    {
      diplay(dis_data_buf);
    }


  }
}


3.2 顯示子模塊流程圖
這里我們介紹的是顯示子函數(shù),子函數(shù)首先是關(guān)閉數(shù)碼管的顯示,這一步稱為消引。然后把顯示的數(shù)據(jù)送給其中一個(gè)數(shù)碼管,最后點(diǎn)亮這個(gè)數(shù)碼管,等到下一次輪尋就再調(diào)用下一個(gè)數(shù)碼管。


//數(shù)碼管的顯示函數(shù)
void diplay(uchar *dis_p)
{
  static uchar temp_num=0;
  static uint flash_time=0;
  //全部關(guān)閉消引
  seg_1=0;
  seg_2=0;
  seg_3=0;
  seg_4=0;
  SEG_DATA=SEG_Table[*(dis_p+temp_num)];    //把數(shù)據(jù)發(fā)送給數(shù)碼管的數(shù)據(jù)接口
  switch(temp_num)    //動(dòng)態(tài)一次掃描各個(gè)數(shù)碼管
  {
  case 0:
    if(set_position==4)
    {
      if(flash_time<50)     //如果社說的時(shí)間小于50那么就打開心事
      {seg_1=1;seg_2=0;seg_3=0;seg_4=0;}
      else if(flash_time<100)//小于100就關(guān)閉顯示
      {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;//循環(huán)四次

  flash_time++;
  if(set_position==0)flash_time=0;      //閃爍


}
3.3 重要的數(shù)據(jù)結(jié)構(gòu)、參數(shù)和函數(shù)分析
//讀取設(shè)定的目標(biāo)數(shù)值
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];     //計(jì)算出計(jì)數(shù)的數(shù)值
   }
   else
   {
     for(i=0;i<4;i++)
     {
        dis_data_buf[ i]=0;
        write_rom(i,dis_data_buf[ i]);
     }
   }
}
這里我們分析一下讀取設(shè)定目標(biāo)數(shù)值的子函數(shù),這個(gè)子函數(shù)在程序的一開始調(diào)用一次,主要是讀取上一次存儲(chǔ)的數(shù)據(jù),防止其掉電丟失。首選讀24C02得到不同地址內(nèi)的數(shù)據(jù),然后根據(jù)存入的順序把數(shù)據(jù)拼接成設(shè)定值給后面使用。
4、項(xiàng)目運(yùn)行效果展示
  這是初始狀態(tài)沒有進(jìn)行操作的時(shí)候,如圖
然后我們點(diǎn)擊啟動(dòng)按鈕,可以看到電機(jī)開始轉(zhuǎn)動(dòng)了,如圖
我們按下模擬光電的開關(guān),實(shí)際數(shù)值增加到設(shè)定值,此時(shí)電機(jī)停止并報(bào)警,如圖
5、總結(jié)與心得體會(huì)
這個(gè)設(shè)計(jì)過程中,我們通過在原有的計(jì)數(shù)器系統(tǒng)進(jìn)行了改進(jìn),使之增添了設(shè)置、啟動(dòng)、停止等的三個(gè)控制功能,并添加了報(bào)警、顯示、存儲(chǔ)等功能,使之成為一個(gè)更加適用,功能更加完備的屬于自己的一個(gè)系統(tǒng)。設(shè)計(jì)結(jié)果能夠符合題意,成功完成了此次設(shè)計(jì)要求,這個(gè)過程中,我們花費(fèi)了大量的時(shí)間和精力,更重要的是,我們?cè)趯W(xué)會(huì)創(chuàng)新的基礎(chǔ)上,同時(shí)還懂得合作精神的重要性,學(xué)會(huì)了與他人合作。我們掌握的僅僅是理論知識(shí),如何去鍛煉我們的實(shí)踐能力?如何把我們所學(xué)的專業(yè)基礎(chǔ)課理論知識(shí)運(yùn)用到實(shí)踐中去呢?我想做類似設(shè)計(jì)就為我們提供了良好的實(shí)踐平臺(tái)。
       在這次設(shè)計(jì)中,我們運(yùn)用到了以前所學(xué)的專業(yè)知識(shí),如:C語(yǔ)言、模擬和數(shù)字電路知識(shí)等。雖然過去從未獨(dú)立應(yīng)用過它們,但在學(xué)習(xí)的過程中帶著問題去學(xué)效率很高,這是我做這次設(shè)計(jì)的又一收獲。
基于Keil C51的單片機(jī)開發(fā)環(huán)境應(yīng)用范圍廣泛,功能強(qiáng)大,但由于自己應(yīng)用不夠熟悉,出現(xiàn)了很多不規(guī)范的情況,使得在調(diào)試過程中遇到很多困難,這是自己軟件開發(fā)能力不足的表現(xiàn),有待提高。本系統(tǒng)通過按鍵進(jìn)行設(shè)定計(jì)數(shù)功能,需要人為現(xiàn)場(chǎng)近距離操作,可考慮通過遙控設(shè)定,改進(jìn)方案后,可遠(yuǎn)距離操作,更好的節(jié)省人力。


6、附錄

單片機(jī)源程序如下:
  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. //數(shù)碼管位選接口
  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                //數(shù)碼管的數(shù)據(jù)接口


  18. //獨(dú)立按鍵
  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. //電機(jī)的控機(jī)制口
  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共陽(yáng)
  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延時(shí)
  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數(shù)據(jù)發(fā)送或接收*/
  50. void start_rom()//在時(shí)鐘線為高,數(shù)據(jù)線從高電平跳到低電平時(shí),開始傳送
  51. {
  52.    SDA=1;           //數(shù)據(jù)先
  53.    delay_us(2);
  54.    SCL=1;           //時(shí)鐘線為高,等數(shù)據(jù)線下降才開始
  55.   delay_us(5);
  56.    SDA=0;           //數(shù)據(jù)線下降拉,啟動(dòng)了
  57.          delay_us(5);
  58.    SCL=0;           
  59. }

  60. /*結(jié)束數(shù)據(jù)傳送*/
  61. void stop_rom()
  62. {  
  63.    SDA=0;            //時(shí)鐘線為高時(shí),數(shù)據(jù)線上升沿為結(jié)束信號(hào)
  64.          delay_us(2);
  65.    SCL=1;
  66.          delay_us(4);
  67.    SDA=1;
  68.          delay_us(4);
  69.    SCL=0;
  70. }

  71. //************************************************************************//
  72. //函數(shù)名稱:void ack_rom()
  73. //函數(shù)功能:ROM應(yīng)答信號(hào)
  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. //函數(shù)名稱:void no_ack_rom()
  88. //函數(shù)功能:無需應(yīng)答
  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. //函數(shù)名稱:void write_byte_rom(uchar data)
  101. //函數(shù)功能:向ROM 寫入字節(jié)
  102. //傳入?yún)?shù):data 待寫入的字節(jié)
  103. //返回參數(shù):無
  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--)//寫數(shù)據(jù)循環(huán),從高位開始
  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. //函數(shù)名稱:void write_rom(uchar addr,uchar data)
  165. //函數(shù)功能:寫數(shù)據(jù)到ROM
  166. //傳入?yún)?shù):addr 寫入的地址
  167. //返回參數(shù):read_data 待寫入的數(shù)據(jù)
  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); //寫入數(shù)據(jù)
  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);//去抖動(dòng)
  212.         if(K_PORT!=temp_data)//有按鍵按下
  213.         {
  214.           key_up=1;
  215.           temp=K_PORT&0xf0;  //取高字節(jié),即列
  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.     //判斷獨(dú)立按鍵
  234.     if((K1==0||K2==0||K3==0))
  235.     {
  236.       key_up=1;
  237.       Delay_1ms(10);//去抖動(dòng)
  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. //數(shù)碼管的顯示函數(shù)
  252. void diplay(uchar *dis_p)
  253. {
  254.   static uchar temp_num=0;
  255.   static uint flash_time=0;
  256.   //全部關(guān)閉消引
  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)];     //把數(shù)據(jù)發(fā)送給數(shù)碼管的數(shù)據(jù)接口
  262.   switch(temp_num)      //動(dòng)態(tài)一次掃描各個(gè)數(shù)碼管
  263.   {
  264.   case 0:
  265.     if(set_position==4)
  266.     {
  267.       if(flash_time<50) //如果社說的時(shí)間小于50那么就打開心事
  268.       {seg_1=1;seg_2=0;seg_3=0;seg_4=0;}
  269.       else if(flash_time<100)//小于100就關(guān)閉顯示
  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;//循環(huán)四次

  340.   flash_time++;
  341.   if(set_position==0)flash_time=0;            //閃爍


  342. }
  343. //計(jì)數(shù)器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. //讀取設(shè)定的目標(biāo)數(shù)值
  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];     //計(jì)算出計(jì)數(shù)的數(shù)值
  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中寫入存儲(chǔ)數(shù)據(jù)
  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. * 功能 : 主函數(shù)                     
  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;                 //關(guān)閉電機(jī)
  395.   BUZZ=1;       //關(guān)閉報(bào)警
  396.   Read_set_num();         //讀取設(shè)定的數(shù)值
  397.   Time0_init();                  // 定時(shí)器初始化

  398.   while(1)
  399.   {            
  400.     Key_num=KEY_Scan();     //掃描按鍵
  401.    
  402.     if(set_mode==0)      //非設(shè)定模式
  403.     {
  404.       if(Key_num==12)          //啟動(dòng)
  405.       {
  406.         counter_buf[0]=0;counter_buf[1]=0;counter_buf[2]=0;counter_buf[3]=0;    //清除顯示
  407.         counter_num=0;               //計(jì)數(shù)清零
  408.         moto=1;                               //打開電機(jī)
  409.                    LED=1;
  410.         BUZZ=1;  //關(guān)閉報(bào)警
  411.         EA=1;                                    //打開計(jì)數(shù)
  412.       }
  413.       else if(Key_num==13)//停止
  414.       {
  415.         moto=0;                     //關(guān)閉電機(jī)
  416.                    LED=1;
  417.         BUZZ=1;//關(guān)閉報(bào)警
  418.         EA=0;                          //關(guān)閉計(jì)數(shù)
  419.       }
  420.       if(Key_num==14) //設(shè)置
  421.       {
  422.         set_mode=1;            //設(shè)置模式置一
  423.         set_position=1;
  424.         moto=0;                     //關(guān)閉電機(jī)     
  425.         EA=0;                         //關(guān)閉計(jì)數(shù)
  426.       
  427.       }
  428.      
  429.      
  430.     }
  431.     else//設(shè)定模式
  432.     {
  433.       if(Key_num==11)//按下了確定鍵
  434.       {
  435.         set_mode=0;//退出設(shè)定
  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]; //計(jì)算出計(jì)數(shù)的數(shù)值
  439.                    Write_set_num();
  440.       }
  441.       else if(Key_num<10)//顯示的設(shè)定值
  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)//清除設(shè)定
  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];     //計(jì)算出計(jì)數(shù)的數(shù)值
  459.    
  460.     if(counter_num>=set_num)  //如果計(jì)數(shù)數(shù)值大于等于設(shè)定的數(shù)值就停止
  461.     {
  462.       moto=0;                          //關(guān)閉電機(jī)
  463.       BUZZ=0;       //打開報(bào)警
  464.            LED=0;//

  465.     }                                                               
  466.     if(set_mode==0)      //正常模式下顯示計(jì)數(shù)值
  467.     {
  468.       diplay(counter_buf);
  469.     }
  470.     else  //設(shè)定模式下顯示設(shè)定值
  471.     {
  472.       diplay(dis_data_buf);
  473.     }
  474.    
  475.    
  476.   }
  477. }

  478. //計(jì)數(shù)器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; //最大計(jì)數(shù)到9999,然后從零開始
  486.     else
  487.     {
  488.       counter_num++;           //計(jì)數(shù)加一
  489.       counter_buf[3]++;
  490.       if(counter_buf[3]>9)  //個(gè)位大于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. }
復(fù)制代碼

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

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

使用道具 舉報(bào)

本版積分規(guī)則

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

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表