<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

          AVR單片機(jī)C語言程序設(shè)計(jì)中的位操作

          作者: 時(shí)間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
          在標(biāo)準(zhǔn)C語言的的教材中,對(duì)于位運(yùn)算的操作是基本不涉及的,但是在單片機(jī)系統(tǒng)的程序中,需要經(jīng)常操作各類以字節(jié)為單位的寄存器,而這些寄存器通常都是以二進(jìn)制中的位為控制單位的數(shù)據(jù)組合。往往一個(gè)8位寄存器中的每一位都有各自的控制對(duì)象,例如端口B的方向寄存器DDRB,如下圖所示


          它實(shí)際上控制著PB口的8個(gè)端口PB0-PB7的方向,也就是說它的每一位都控制一個(gè)端口的方向,如果我們要把端口PB0-PB3設(shè)置為輸出口,而把PB4-PB7設(shè)置為輸入口,在不用位運(yùn)算符的情況下,我們可以直接使用賦值語句DDRB=0x0f來實(shí)現(xiàn),這樣是完全可以實(shí)現(xiàn)的。
          但是如果出現(xiàn)下面的情況:在程序中PB口的8位端口的狀態(tài)本來是1、3、5、7為輸入。0、2、4、6為輸出(即DDRB=0x55),接下來要將PB口的第1位設(shè)置為輸出,其它端口的狀態(tài)不變,然后又要將第2位設(shè)置為輸入,其它端口的狀態(tài)不變。該怎么實(shí)現(xiàn)?也許我們?nèi)匀豢梢允褂觅x值語句來實(shí)現(xiàn),比如DDRB=0x55;接下來設(shè)置DDRB=0x57;然后再設(shè)置DDRB=0x53;首先要肯定的是,這種做法是絕對(duì)正確的。但是我們可能有沒有注意到,在改變其中一位的值的時(shí)候,我們同時(shí)還要考慮其它7位的狀態(tài),并且要小心翼翼的避免不小心改變了其它位的值。
          那么有沒有一種方法,可以簡(jiǎn)單的實(shí)現(xiàn)修改某一位的狀態(tài),同時(shí)不會(huì)改變其它位的狀態(tài)呢?
          這就牽出了單片機(jī)C語言程序設(shè)計(jì)中的位運(yùn)算的概念。
          我們來看這個(gè)語句:DDRE |= (1 << PE5); 這個(gè)語句實(shí)現(xiàn)的功能是將PE口的第5位設(shè)置為輸出口,其余口的狀態(tài)不變。它是怎么實(shí)現(xiàn)的?首先我們來看1 << PE5這個(gè)表達(dá)式,我們前面已經(jīng)介紹了,AVR各寄存器的宏定義是在頭文件io.h中定義好的,我們可以直接調(diào)用,現(xiàn)在

          本文引用地址:http://www.ex-cimer.com/article/201611/318725.htm

          我們就來看看在io.h中PE5是如何定義的(在WINAVR的安裝目錄下查找iom64.h),我們可以看到PE口的8位分別定義如下:
          /* Port E Data Register - PORTE */
          #define PE7 7
          #define PE6 6
          #define PE5 5
          #define PE4 4
          #define PE3 3
          #define PE2 2
          #define PE1 1
          #define PE0 0
          可以看出,實(shí)際上PE5=5;那么1 << PE5,就很容易理解了,它的作用是把1左移5位,最后的結(jié)果按照二進(jìn)制表示就是0b00100000,而DDRE|= (1 << PE5);實(shí)際上是DDRE= DDRE | (1 << PE5);首先“|”表示的是“或”操作,DDRE是端口E的方向寄存器,在iom64.h中定義為:

          #define DDRE _SFR_IO8(0x02);它實(shí)際上是定義了一個(gè)標(biāo)識(shí)符,這個(gè)標(biāo)識(shí)符對(duì)應(yīng)數(shù)據(jù)存儲(chǔ)區(qū)RAM中的某個(gè)地址,這個(gè)我們暫且不去深究。我們還是回過頭來看DDRE= DDRE | (1 << PE5);這句話實(shí)現(xiàn)的功能,這句話實(shí)際上是將寄存器DDRE中的內(nèi)容(數(shù)據(jù))跟二進(jìn)制數(shù)0b00100000進(jìn)行或操作,我們知道兩個(gè)數(shù)的或操作的結(jié)果是:只要有一個(gè)是1,結(jié)果就是1.那么假如DDRE中本來的值是0b10001010(0x8a),它和0b00100000進(jìn)行“或”操作以后的結(jié)果變成了0b10101010(0xaa)。我們可以看出,相或以后DDRE中的第5位以外的各位的值都沒有改變,而第5位變成了1,我們的目的就是要將第5位設(shè)為輸出口(即將第5位設(shè)置為1)。
          現(xiàn)在我們來看一下從語言中有幾種位運(yùn)算符:
          移位運(yùn)算符:左移<<,右移>>
          與運(yùn)算符:&
          或運(yùn)算符:|
          取反運(yùn)算符:~
          異或運(yùn)算符:^
          就這些了,總共只有6種位運(yùn)算符?,F(xiàn)在我們來看一下這些運(yùn)算符都起什么作用;
          左移運(yùn)算符:表達(dá)形式為x< 例如,x是一個(gè)unsigned char類型的數(shù)據(jù)(即x是一個(gè)單字節(jié)數(shù)據(jù),共有8位),設(shè)x的初值為0x00000001,執(zhí)行x<n=0時(shí),x<n=1時(shí),x<n=2時(shí),x<...
          n=7時(shí),x<n=8時(shí),x< 從結(jié)果來看,當(dāng)n在1-7之間取值時(shí),運(yùn)算的結(jié)果總是1依次向左移動(dòng)一位,但是當(dāng)n>=8以后,x的值就一直是0了,這是因?yàn)閤是一個(gè)只有8位的整形變量,它的最大二進(jìn)制長度是8位,當(dāng)n超過8以后,移位操作的結(jié)果已經(jīng)超出8位的范圍了,產(chǎn)生了溢出現(xiàn)象。
          右移的原理跟左移相似,只是它的運(yùn)算結(jié)果跟左移剛好相反。
          在單片機(jī)C語言編程中,經(jīng)常使用移位操作來實(shí)現(xiàn)將數(shù)據(jù)乘以(左移)或除以(右移)2的n次方的乘除運(yùn)算,利用移位操作實(shí)現(xiàn)乘除運(yùn)算可以顯著提高單片機(jī)的運(yùn)算速度和效率。其詳細(xì)原理我們可以翻閱相關(guān)的C語言書籍來進(jìn)行更深了解。
          “取反”、“與”、“或”、“非”運(yùn)算經(jīng)常用于對(duì)寄存器的某一位進(jìn)行操作,
          例如,使端口B的第二位輸出高電平,同時(shí)不改變其余端口的狀態(tài),我們可以采用如下方法:
          PORTB |= (1<實(shí)際上,想將一個(gè)8位寄存器的某一位設(shè)置為1,可以采用這樣的語句:寄存器名(如PORTB) |= (1 << X),式中X表示第X位。
          相反的,如果想將一個(gè)8位寄存器的某一位設(shè)置為0,可以采用這樣的語句:寄存器名(如PORTB) &= ~(1 << X),式中X表示第X位。

          寫著的時(shí)候,總感覺心里清楚,但是表達(dá)不出來,本來是想結(jié)合單片機(jī)來講解如何用C語言來開發(fā)單片機(jī)程序的,但總是沒有辦法將兩者的結(jié)合很直觀的表達(dá)出來。有些困惑!
          這或許就是現(xiàn)在市面上相當(dāng)多的講解單片機(jī)C語言開發(fā)的書為什么總是將C語言的講解和具體的程序設(shè)計(jì)分開來講的原因吧。大家都沒有更好的辦法在講解具體的單片機(jī)開發(fā)的同時(shí)把C語言的知識(shí)逐步融合到實(shí)例中



          評(píng)論


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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();