新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 單片機(jī)C語言位操作實(shí)例

        單片機(jī)C語言位操作實(shí)例

        作者: 時(shí)間:2016-11-24 來源:網(wǎng)絡(luò) 收藏
        C語言本身有較強(qiáng)的位處理功能,但在控制領(lǐng)域有時(shí)候經(jīng)常需要控制某一個(gè)二進(jìn)制中的某一位,為此在MCS_51的KEIL C51中擴(kuò)充了兩個(gè)數(shù)據(jù)類型bit和sbit。前者可以在MCS_51的位尋址區(qū)進(jìn)行分配,而后者只能定義為可位尋址的特殊功能寄存器SFR中的某一位。這兩個(gè)擴(kuò)充為MCS_51應(yīng)用C語言編程帶來很大的方便。AVR的C語言中除了CodeVisionAVR定義了bit數(shù)據(jù)類型外,其余都沒有類似的定義,而sbit類型所有C語言都沒有定義。相比較,進(jìn)行位操作運(yùn)算CodeVisionAVR的功能最強(qiáng),它一方面有bit類型的數(shù)據(jù),可用于位運(yùn)算;另外在訪問寄存器時(shí)可以直接訪問寄存器的某一位,例如訪問DDRB的B2位可以這樣訪問:
        DDRB.3 = 1;
        而在IAR、ICCAVR和GCCAVR中沒有bit類型的運(yùn)算,當(dāng)它們需要訪問寄存器的某一位時(shí),只能使用ANSI C語言的位運(yùn)算功能。
        C語言是為描述系統(tǒng)而設(shè)計(jì),因此它具有匯編語言所能完成的一些功能,有較好的位操作指令:“&”,“|”,“~”、“<<”、“>>”。在控制領(lǐng)域,經(jīng)常需要控制某一個(gè)二進(jìn)制位,標(biāo)準(zhǔn)C有兩種方法實(shí)現(xiàn)單個(gè)位的操作。
        1. 用“讀-修改-寫”實(shí)現(xiàn)對單個(gè)位的操作
        在沒有單個(gè)位的位操作指令的情況下,一般是采用“讀-修改-寫”的方法實(shí)現(xiàn)單個(gè)位的位操作,即:
        Ø 通過與0“與”操作,將某一位清0。例如,使i變量的第0位為0,實(shí)現(xiàn)方法為:i = i&0xfe;
        Ø 通過與1相 “或”操作,將某一位置1。例如,使i變量的第0位為1,實(shí)現(xiàn)方法為 i = i|0x01;
        Ø 通過與1進(jìn)行“異或”操作,將某一位取反。例如,使i變量的第0位取反,實(shí)現(xiàn)方法為 i = i^0x01。
        注意:采用“讀-修改-寫”的方法時(shí)不要影響其他位。即某位清0時(shí),其他位與1相 “與”;某位置1時(shí),其他位與0“或”;取反時(shí),其他位與0“異或”。
        很多程序員喜歡采用下面的移位方式,語句簡練:
        #define bit(x) (1<<(x))
        #define LED 2
        PORTB|= bit(LED); //將PORTB第二位置1,點(diǎn)亮連接在I/O口的LED
        該方式下,程序運(yùn)行時(shí)會(huì)增加移位操作,生成的代碼較大。若按如下方式直接定義生成的代碼就不會(huì)有移位操作:
        #define LED 0X04
        PORTB |= LED;
        也有程序員采取如下宏定義的方法實(shí)現(xiàn)單個(gè)位的操作,使用十分方便:
        #define SET_BIT(x,y) ((x)|=(0x0001<<(y)))//置x的第y位
        #define CLR_BIT(x,y) ((x)&=~( 0x0001<<(y)))//清x的第y位為0 #define CPL_BIT(x,y) ((x)^= (0x0001<<(y)))//取反x的第y位
        #define GET_BIT(x,y) (((x)&(1<讀取x的第y位
        #define LET_BIT(x,y,z) ((x)=(x)&(~(1<<(y)))|((z)<<(y)))//
        將x的第y位寫上z(0/1)
        2. 通過位域的(Bit Field )的方法實(shí)現(xiàn)位操作
        在系統(tǒng)寄存器設(shè)置時(shí),很多時(shí)候并不需要修改完整的字節(jié),而是只修改一個(gè)或幾個(gè)位,標(biāo)準(zhǔn)C提供了一種基于結(jié)構(gòu)體的數(shù)據(jù)結(jié)構(gòu)——位域。位域就是把一個(gè)存儲單元中的二進(jìn)制劃分為幾個(gè)不同的區(qū)域,并說明每個(gè)區(qū)域的位數(shù),每個(gè)域有一個(gè)域名,允許在程序中按域名進(jìn)行操作。位域的定義格式如下:
        Struct 位域結(jié)構(gòu)名
        {
        位域列表;
        };
        位域列表格式為:類型說明符 位域名:位域長度
        Struct k
        {
        unsigned int a:1;
        unsigned int :2;
        unsigned int b:3;
        unsigned int :0;//空域
        }k1;
        說明:
        Ø 各位依次從低位到高位排列,排滿一個(gè)存儲單元,按地址接著排下一個(gè)單元。
        Ø 位域可以無域名,但不能被引用。例如,第2域,這時(shí)它只用來填充和調(diào)整位置。
        Ø 第四行稱為空域,目的是將目前存儲單元的剩余部分分為一個(gè)域,且填充0。
        位域的引用,例如;
        k1.a = 1;//置k1的BO位為1
        k1.b = 7;//置k1的B3-B5位為111
        用位域定義位變量,操作I/O口,產(chǎn)生的代碼緊湊、高效。定義的方法如下;
        typedef struct INT8_bit_struct
        {
        unsigned bit0:1; unsigned bit1:1; unsigned bit2:1;
        unsigned bit3:1; unsigned bit4:1; unsigned bit5:1;
        unsigned bit6:1;unsigned bit7:1;
        }bit_field;
        再次宏定義每一個(gè)位,使用方法如下:
        #define _PINB 0x23
        #define _PORTB 0X25
        …………
        #define IOB2i (*(volatile bit_field *)(_PINB)).bit2
        #define IOB2o (*(volatile bit_field *)(_PORTB)).bit2
        例如:
        void main(void)
        {
        unsigned char I;
        IOB2o = 0;//B口B2位輸出低電平
        i = IOB2i;//讀B口B2位,將B口B2位上的電平值送給i
        //
        }
        對于沒有擴(kuò)展位變量的C語言環(huán)境,在匯編下沒有單個(gè)位的位操作的MCU,通過位域的方法操作I/O口是最佳的方法;匯編下有單個(gè)位的位操作指令的MCU,可以嵌入式匯編,但是程序的移植性可能會(huì)下降,建議使用位域的方法進(jìn)行操作比較合適。


        關(guān)鍵詞: 單片機(jī)C語言位操

        評論


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

        關(guān)閉
        主站蜘蛛池模板: 尼木县| 新平| 元谋县| 江门市| 阳江市| 荥阳市| 吴江市| 甘肃省| 项城市| 郁南县| 五华县| 平阴县| 佛冈县| 梓潼县| 临泽县| 琼结县| 华坪县| 乐业县| 高要市| 青浦区| 祁阳县| 东港市| 石林| 马尔康县| 临沭县| 大洼县| 玉树县| 修武县| 石河子市| 卢氏县| 镇原县| 寻乌县| 古蔺县| 阿勒泰市| 孟州市| 翁源县| 织金县| 伊宁市| 天祝| SHOW| 寿阳县|