新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 用單片機(jī)pic16f877a實現(xiàn)鼠標(biāo)數(shù)據(jù)的采集

        用單片機(jī)pic16f877a實現(xiàn)鼠標(biāo)數(shù)據(jù)的采集

        作者: 時間:2016-12-03 來源:網(wǎng)絡(luò) 收藏
        最近弄個用單片機(jī)pic16f877a實現(xiàn)鼠標(biāo)數(shù)據(jù)的采集。通過對鼠標(biāo)底層通信原理與協(xié)議的分析,以單片機(jī)pic16f877a構(gòu)成鼠標(biāo)數(shù)據(jù)的采集的實現(xiàn)和液晶1602顯示的實現(xiàn)。

        本文引用地址:http://www.104case.com/article/201612/325224.htm

        現(xiàn)在繼續(xù)寫下去 !!!!!!盡管和比賽沒有關(guān)系了

        一、先要熟悉鼠標(biāo)的協(xié)議和接口

        下面是PS2的接口

        這是鼠標(biāo)在傳輸過程中數(shù)據(jù)的一個幀:

        一個開始位:(為0)

        八個數(shù)據(jù)位:

        一個奇校驗位:

        一個停止位:(它總是1)

        鼠標(biāo)和單片機(jī)通信:

        1、單片機(jī)給鼠標(biāo)發(fā)命令是按下面的格式進(jìn)行的:

        (注意:一個應(yīng)答信號的接收)

        這是它的詳細(xì)過程:

        2、鼠標(biāo)向單片機(jī)傳送數(shù)據(jù)是下面的格式:

        二、下面就是設(shè)計鼠標(biāo)和單片機(jī)的通信電路:(可以參考下面這個接法)

        (注意:數(shù)據(jù)和時鐘都這是集電極開路的結(jié)構(gòu),平時是高電平 )

        三、外圍布置好了就是具體程序的實現(xiàn)

        我們可以采用單片機(jī)16F877A的外部中斷來響應(yīng)鼠標(biāo)的時鐘,在中斷中接收數(shù)據(jù)。

        我 們可按下面的步驟實現(xiàn):

        1)把時鐘線拉低至少100微秒
        2)把數(shù)據(jù)線拉低
        3)釋放數(shù)據(jù)線
        4)等待設(shè)備把時鐘線拉低
        5)設(shè)置/復(fù)位數(shù)據(jù)線發(fā)送第一個數(shù)據(jù)位
        6)等待設(shè)備把時鐘拉高
        7)等待設(shè)備把時鐘拉低
        8)重復(fù)5-7步發(fā)送剩下的7個數(shù)據(jù)位和校驗位
        9)釋放數(shù)據(jù)線

        10)等待設(shè)備把數(shù)據(jù)線拉低
        11)等待設(shè)備把時鐘線拉低
        12)等待設(shè)備釋放數(shù)據(jù)線和時鐘線

        程序如下:

        //外部中斷INT0初始化
        void INTE_init(void)
        {
        INTCON=0X00;
        GIE=1; //總中斷
        RBPU=0;
        //INTE=1;//外部中斷
        //INTEDG=0;//下升沿觸發(fā)有效
        INTEDG=1;//上升沿觸發(fā)有效
        TRISB=0x00;//正常工作下時鐘RB0和數(shù)據(jù)RB2均輸入
        INTF=0;//這三句是開外部中斷
        PORTB=0X00;
        }

        //發(fā)送數(shù)據(jù)
        //發(fā)送11位數(shù)據(jù):1START-8DATA-1PARITY-1STOP
        //并接收一個應(yīng)答位ack = 0
        void mouse_write_dat(unsigned char dat)
        {
        unsigned char i; //循環(huán)變量

        INTE = 0; //關(guān)閉外部中斷

        asm( "nop");
        mouse_clk = 0; //拉低時鐘線
        delay(33); //至少延時100us
        mouse_sda = 0; //發(fā)送起始位

        mouse_clk = 1; //釋放時鐘線
        mouse_sda = 1; //釋放數(shù)據(jù)線

        TRISB0=1;//時鐘輸入
        asm( "nop");
        TRISB=0X01;

        for(i = 0; i < 8; i++)
        { //至少要在25us內(nèi)完成發(fā)送一位

        while(!mouse_clk); //等待設(shè)備把時鐘線拉高

        mouse_sda =(bit)(dat& 0x01);//先發(fā)送最低位
        dat >>= 1; //下降沿寫入數(shù)據(jù)

        while(mouse_clk); //等待設(shè)備把時鐘線拉低

        }

        while(!mouse_clk); //等待設(shè)備把時鐘線拉高
        mouse_sda = 0; //發(fā)送奇校驗位
        while(mouse_clk); //等待設(shè)備把時鐘線拉低

        while(!mouse_clk); //等待設(shè)備把時鐘線拉高
        mouse_sda = 1; //發(fā)送停止位
        while(mouse_clk); //等待設(shè)備把時鐘線拉低

        TRISB2=1;//數(shù)據(jù)輸入
        asm( "nop");
        asm( "nop");

        while(!mouse_clk); //等待設(shè)備把時鐘線拉高
        while(mouse_sda); //等待接收應(yīng)答位(總是為0)
        while(mouse_clk); //等待設(shè)備把時鐘線拉低

        while(!mouse_clk); //等待設(shè)備釋放時鐘線
        while(!mouse_sda); //等待設(shè)備釋放數(shù)據(jù)線

        INTE = 1; //打開外部中斷INTE
        }

        再就是鼠標(biāo)的發(fā)數(shù)據(jù)模塊可以參考下面的步驟:

        1)等待時鐘線為高
        2)數(shù)據(jù)線仍然為低嗎 有錯誤發(fā)生放棄
        3)讀入8個數(shù)據(jù)位在讀入這些位后
        4)讀入校驗位>測試時鐘線數(shù)否被主機(jī)拉低
        5)讀入停止位/這就意味著放棄這次傳送
        6)數(shù)據(jù)線仍舊為0嗎
        是保持時鐘直到數(shù)據(jù)1然后產(chǎn)生一個錯誤
        7)輸出應(yīng)答位
        8)檢查校驗位
        如果校驗位不正確則產(chǎn)生一個錯誤
        9)延遲45微秒給主機(jī)時間抑制下次的傳送
        按如下次序讀取每位8個數(shù)據(jù)位檢驗位和停止位
        1)延遲20微秒
        2)把時鐘拉低
        3)延遲40微秒
        4)釋放時鐘
        5)延遲20微秒
        7)讀數(shù)據(jù)線
        按如下次序發(fā)送應(yīng)答位
        1)延遲15微秒
        2)把數(shù)據(jù)線拉低
        3)延遲5微秒
        4)把時鐘線拉低
        5)延遲40微秒
        6)釋放時鐘線
        7)延遲5微秒
        8)釋放數(shù)據(jù)線

        void interrupt INTE_ISR(void)
        {

        mouse_word >>= 1; //先向右空移一位

        if(mouse_sda) {mouse_word |= 0x0400; } //11位數(shù)據(jù)先接收最低位0000 010 (0 0000 000) 0 1START-8DATA-1PARITY-1STOP
        n++; if(n == 11) {mouse_read_dat(); n = 0;} //接收完成則讀出數(shù)據(jù)
        INTF=0;
        }

        接下來就是讀鼠標(biāo)的數(shù)據(jù)了,首先要明白這個數(shù)據(jù)包中具體是些什么,看下面的圖:

        (一般的鼠標(biāo)就這些,具體的就要查鼠標(biāo)的資料了)同志們 還不清楚就看下面的解釋吧!!!

        鼠標(biāo)內(nèi)部有一個位移計數(shù)器,位移計數(shù)器是一個9位2的補碼整數(shù)。它的最高位作為

        符號位出現(xiàn)在位移數(shù)據(jù)包的第一個字節(jié)里。這些計數(shù)器在鼠標(biāo)讀取輸入發(fā)現(xiàn)有位移

        時被更新。這些值是自從最后一次發(fā)送位移數(shù)據(jù)包給主機(jī)后位移的累計量(即最后

        一次包發(fā)給主機(jī)后位移計數(shù)器被復(fù)位)。位移計數(shù)器可表示的值的范圍是-255到+255,

        如果超過了范圍,相應(yīng)的溢出位就被設(shè)置,并且在復(fù)位前,計數(shù)器不會增減。正如我前

        面提及的一旦位移數(shù)據(jù)包成功地發(fā)送給主機(jī),位移計數(shù)器就會復(fù)位,同樣鼠標(biāo)在收到主機(jī)

        不是Resend 0xFE命令外的其他命令,計數(shù)器也會復(fù)位。



        評論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 胶南市| 双柏县| 富源县| 清水河县| 驻马店市| 曲阜市| 通州市| 潼关县| 电白县| 尖扎县| 溧阳市| 成都市| 互助| 滨海县| 伊春市| 祁阳县| 伊吾县| 舟山市| 盖州市| 东安县| 太湖县| 鄂尔多斯市| 永州市| 庆安县| 昌图县| 专栏| 和硕县| 新宁县| 潍坊市| 达日县| 长沙市| 大石桥市| 黄平县| 仪陇县| 凤城市| 永春县| 中牟县| 商洛市| 九江市| 贵州省| 尖扎县|