C語言 | 位操做的一些技巧

1024G 嵌入式資源大放送!包括但不限於C/C++、單片機、Linux等。關注微信公衆號【嵌入式大雜燴】,回覆1024,便可免費獲取!git

操做位有兩種方法,一種是位字段,另外一種是使用按位運算符。位字段的方法可查看往期筆記:【C語言筆記】位域。本文介紹使用按位運算符操做位的方法。下表爲幾種位操做符及其含義:github

位操做符

不改變其餘位的值的情況下,對某幾個位進行設值

嵌入式編程中,經常須要對一些寄存器進行配置,有的狀況下須要改變一個字節中的某一位或者幾位,可是又不想改變其它位原有的值,這時就可使用按位運算符進行操做。下面進行舉例說明,假若有一個8位的TEST寄存器:
TEST寄存器編程

當咱們要設置第0位bit0的值爲1時,可能會這樣進行設置:微信

TEST = 0x01;

可是,這樣設置是不夠準確的,由於這時候已經同時操做到了高7位:bit1~bit7,若是這高7位沒有用到的話,這麼設置沒有什麼影響;可是,若是這7位正在被使用,結果就不是咱們想要的了。markdown

在這種狀況下,咱們就能夠借用「&」和「|」進行配置。ide

對於二進制位操做來講,無論該位原來的值是0仍是1,它跟0進行&運算,獲得的結果都是0,而跟1進行&運算,將保持原來的值不變;無論該位原來的值是0仍是1,它跟1進行|運算,獲得的結果都是1,而跟0進行|運算,將保持原來的值不變。函數

因此,此時能夠設置爲:ui

TEST = TEST | 0x01;

其意義爲:TEST寄存器的高7位均不變,最低位變成1了。在實際編程中,常改寫爲:.net

TEST |= 0x01;

這種寫法能夠必定程度上簡化代碼,是 C 語言經常使用的一種編程風格。code

一樣的,要給TEST的低4位清0,高4位保持不變,能夠進行以下配置:

TEST &= 0xF0;

這個場景單片機開發中常用,方法就是先對須要設置的位用&操做符進行清零操做,而後用|操做符設值。好比我要改變GPIOA的狀態,能夠先對寄存器的值進行&清零操做:

GPIOA->CRL &= 0XFFFFFF0F; //將第4-7位清0

而後再與須要設置的值進行|或運算:

GPIOA->CRL |= 0X00000040; //設置相應位的值,不改變其餘位的值
移位操做提升代碼的可讀性。

移位操做在單片機開發中也很是重要,下面讓咱們看看固件庫的GPIO初始化的函數裏面的一行代碼:

GPIOx->BSRR = (((uint32_t)0x01) << pinpos);

這個操做就是將BSRR寄存器的第pinpos位設置爲1,爲何要經過左移而不是直接設置一個固定的值呢?其實,這是爲了提升代碼的可讀性以及可重用性。這行代碼能夠很直觀明瞭的知道,是將第pinpos位設置爲1。若是你寫成:

GPIOx->BSRR = 0x0030;

這樣的代碼就很差看也很差重用了。
相似這樣的代碼不少:

GPIOA->ODR |= 1 << 5; //PA.5輸出高,不改變其餘位

這樣咱們一目瞭然,5告訴咱們是第5位也就是第6個端口,1告訴咱們是設置爲1了。

~取反操做使用技巧

SR寄存器的每一位都表明一個狀態,某個時刻咱們但願去設置某一位的值爲0,同時其餘位都保留爲1,簡單的做法是直接給寄存器設置一個值:

TIMx->SR = 0xFFF7;

這樣的做法設置第3位爲0,可是這樣的做法一樣很差看,而且可讀性不好。看看庫函數代碼中怎樣使用的:

TIMx->SR = (uint16_t)~TIM_FLAG;

而TIM_FLAG 是經過宏定義定義的值:

#define TIM_FLAG_Update  ((uint16_t)0x0001)
#define TIM_FLAG_CC1     ((uint16_t)0x0002)
#define TIM_FLAG_CC2     ((uint16_t)0x0004)
#define TIM_FLAG_CC3     ((uint16_t)0x0008)
#define TIM_FLAG_CC4     ((int16_t)0x0010)
#define TIM_FLAG_COM     ((uint16_t)0x0020)
#define TIM_FLAG_Trigger ((uint16_t)0x0040)
#define TIM_FLAG_Break   ((uint16_t)0x0080)
#define TIM_FLAG_CC1OF   ((uint16_t)0x0200)
#define TIM_FLAG_CC2OF   ((uint16_t)0x0400)
#define TIM_FLAG_CC3OF   ((uint16_t)0x0800)
#define TIM_FLAG_CC4OF   ((uint16_t)0x1000)

即設置SR第3位爲0時可設置爲:

TIMx->SR = (uint16_t)~TIM_FLAG_CC3;

以上就是關於位操做在嵌入式編程中的一些技巧,若有錯誤,歡迎指出!

參考資料:

《STM32F1開發指南-庫函數版本_V3.1 》

《手把手教你學51單片機》

相關文章
相關標籤/搜索