欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

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

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 2832|回復(fù): 0
收起左側(cè)

單片機(jī)--放下Delay,立地成佛

[復(fù)制鏈接]
ID:59284 發(fā)表于 2014-2-26 19:29 | 顯示全部樓層 |閱讀模式
最近通過(guò)專(zhuān)業(yè)綜合實(shí)驗(yàn)接觸單片機(jī)編程。對(duì)歷程中的Delay函數(shù)有所疑問(wèn),最終在大神們的幫助下解決。寫(xiě)了筆記備忘一下。

問(wèn)題的出現(xiàn):不管是郭天祥的單片機(jī)教程,還是開(kāi)發(fā)板配套資料,都會(huì)用到類(lèi)似函數(shù)來(lái)完成延時(shí):
void Delay(unsigned int t)
{                             
unsigned int k;
while(t--)
{
for(k=0; k<80; k++)
;
}
}

例如在按鍵檢測(cè)中,線(xiàn)delay一會(huì)兒來(lái)完成去抖動(dòng),檢測(cè)按下后再delay一會(huì)兒來(lái)完成等待彈起。再比如在數(shù)碼管顯示中,控制第一個(gè)數(shù)碼管顯示,delay一會(huì)再控制第二個(gè),否則就會(huì)導(dǎo)致整個(gè)數(shù)碼管都被刷亮,一直顯示8。再比如步進(jìn)電機(jī)控制,先發(fā)110000再發(fā)011000之間用delay來(lái)控制轉(zhuǎn)速,delay的久轉(zhuǎn)的慢。

但是如果需要程序通過(guò)按鍵來(lái)控制步進(jìn)電機(jī)的速度,同時(shí)將控制參數(shù)顯示在數(shù)碼管上。這時(shí)問(wèn)題就出現(xiàn)了:在檢測(cè)按鍵的時(shí)候電機(jī)不轉(zhuǎn)了,數(shù)碼管也不現(xiàn)實(shí)了,因?yàn)镃PU在delay,在做沒(méi)有用的空運(yùn)算。同樣的,控制電機(jī)轉(zhuǎn)的時(shí)候數(shù)碼管也不亮了,按鍵也不能檢測(cè)了。控制數(shù)碼管也是同理。可見(jiàn)歷程中每個(gè)模塊的代碼都是不可復(fù)用的,不可擴(kuò)展的。那么怎么寫(xiě)出可復(fù)用、可擴(kuò)展的單片機(jī)程序呢。

問(wèn)題的解決:先把這種方法起個(gè)名字就叫帶計(jì)數(shù)的輪詢(xún)模式吧。
    CPU.h中:
    unsigned int CPU_Count = 0;  //全局變量CPU循環(huán)計(jì)數(shù)
    main.cpp中:
    #include "CPU.h"
    #include "...  //其他設(shè)備控制
    void main()
    {
         while(1)
         {
              CPU_Count ++ ;


              ProcessingMotor(); //電機(jī)控制

              ProcessingLED();   //LED顯示

              ProcessingKey();   //按鍵檢測(cè)
         }   
    }


下面看具體的ProcessingMotor的實(shí)現(xiàn)。
    在Motor.h中
    #define GPIO_MOTOR P1
    unsigned char code FFW[8]={0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9}; //反轉(zhuǎn)順序
    unsigned char code FFZ[8]={0xf9,0xf8,0xfc,0xf4,0xf6,0xf2,0xf3,0xf1}; //正轉(zhuǎn)順序
    unsigned char Direction,Speed;
    void  Motor()
    {
if(Speed == 0)
return;
if(CPU_Count%Speed == 0)
{
if(Direction==1)
GPIO_MOTOR = FFW[(CPU_Count/Speed)%8]&0x1f;  //取數(shù)據(jù)
if(Direction==2)
GPIO_MOTOR = FFZ[(CPU_Count/Speed)%8]&0x1f;
}                 
     }

我們可以通過(guò)CPU_Count%Speed==0來(lái)控制while循環(huán)幾次來(lái)進(jìn)行一次脈沖發(fā)送,同時(shí)可以通過(guò)(CPU_Count/Speed)%8的值來(lái)得到該發(fā)地幾個(gè)波了。這樣CPU就可以得到充分的利用。

LED的控制也是類(lèi)似,這里就不再贅述。


可復(fù)用可擴(kuò)展的按鍵檢測(cè)
其實(shí)按鍵檢測(cè)關(guān)鍵就在兩個(gè)地方,一個(gè)是按鍵接在哪個(gè)引腳上,一個(gè)是按鍵按下應(yīng)該響應(yīng)那個(gè)函數(shù)。如果我們能通過(guò)一些后臺(tái)機(jī)制,最終實(shí)現(xiàn)一個(gè)接口:connectButton(uchar PX,uchar PMask,(*SLOT)());以后再需要用到按鍵的檢測(cè),只需要寫(xiě)一個(gè)按鍵按下對(duì)應(yīng)的函數(shù),并調(diào)用connectButton即可。

那么怎么樣實(shí)現(xiàn)這樣一個(gè)借口呢?

首先我們使用這樣一種檢測(cè)按鍵的方法。在CPU的while循環(huán)中每次都去讀按鍵的狀態(tài),如果按鍵按下測(cè)PressCount++;如果按鍵沒(méi)有按下則unPressCount++;在pressCount加到一個(gè)臨界值說(shuō)明按鍵按下,同時(shí)將unPressCount清零。unPressCount加到一個(gè)臨界值,說(shuō)明按鍵彈起,將pressCount清零。

下面是代碼實(shí)現(xiàn):
     typedef void(*SLOT)();
     #define B_CNT 4
     unsigned char listSize = 0;
     typedef struct ButtonNode
     {
unsigned char isPressed;    //是否被按下
unsigned char px; // 標(biāo)記P0等
unsigned char pmask;    // 標(biāo)記P0等第幾個(gè)管腳
unsigned int pressCount; //cpu一次輪轉(zhuǎn)中,如果被按下則加一
unsigned int unPressCount; //cpu一次輪轉(zhuǎn)中,如果彈起則加一
SLOT func;                      //回調(diào)函數(shù)
      }ButtonNode;
      ButtonNode Button[B_CNT]

這里用的是結(jié)構(gòu)體的數(shù)組來(lái)保存需要的檢測(cè)的按鍵,其實(shí)最好用鏈表動(dòng)態(tài)申請(qǐng)空間,因?yàn)橛面湵聿拍苷嬲龑?shí)現(xiàn)開(kāi)閉性,不用對(duì)代碼做任何修改。而我們這里為了節(jié)約內(nèi)存,每次都要修改檢測(cè)的按鍵個(gè)數(shù)B_CNT。

然后實(shí)現(xiàn)ProcessingKey,對(duì)保存的按鍵信息進(jìn)行循環(huán)檢測(cè)。
void ProcessingKey()
{
unsigned char num = CPU_Count%BUTTON_NUM;
unsigned char p;
if( num >= listSize)
return;
switch (Button[num].px)
       {
        case P0_X:
            p = P0;
        break;
        case P1_X:
             p = P1;
        break;
        case P2_X:
            p = P2;
        break;
        case P3_X:
            p = P3;
        break;
    }
if(!((p >> Button[num].pmask) & 1))
{
Button[num].pressCount ++ ;
if(Button[num].pressCount==150)
{
Button[num].pressCount=0;
if(Button[num].isPressed==0)
{
Button[num].func();
Button[num].isPressed = 1;
Button[num].unPressCount=0;
}
}
}else
{
Button[num].unPressCount ++;
if(Button[num].unPressCount==150)
{
Button[num].unPressCount=0;
if(Button[num].isPressed==1)
{
Button[num].isPressed = 0;
Button[num].pressCount=0;
}
}
}
    }

這里我們使用150次作為臨界值。

最后我們來(lái)實(shí)現(xiàn)最想要的接口connectButton:
void connectButton(unsigned char _px,unsigned char _pmask,SLOT _func)
{
Button[listSize].isPressed = 0;
Button[listSize].px = _px;
Button[listSize].pmask = _pmask;
Button[listSize].pressCount = 0;
Button[listSize].unPressCount = 0;
Button[listSize].func = _func;
listSize ++;
     }
大功告成。該enjoy it了。
以后我們的單片機(jī)程序要使用某個(gè)按鍵按下執(zhí)行一些內(nèi)容時(shí),只需要這樣
實(shí)現(xiàn)按下后的響應(yīng)
void onP3_0Pressed(){  ...  }
調(diào)用connectButton(P3_X,0,onP3_0Pressed)
只要你使用的是計(jì)數(shù)輪詢(xún)模式,那么按鍵檢測(cè)就可以直接實(shí)現(xiàn)了。

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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